mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-31 00:21:31 +00:00
Compare commits
615 Commits
stdlib/sco
...
move_fixes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11e9e7b552 | ||
|
|
2f95131368 | ||
|
|
d6599c8b83 | ||
|
|
048d1c0365 | ||
|
|
cd1420f7c1 | ||
|
|
4bcde41e8c | ||
|
|
6b6736fd55 | ||
|
|
b67a77404e | ||
|
|
f186e9f11f | ||
|
|
d774807204 | ||
|
|
a4e35011e4 | ||
|
|
d14f341187 | ||
|
|
6cbdb53433 | ||
|
|
7a5f94129c | ||
|
|
e25e19c4d6 | ||
|
|
c50881fd02 | ||
|
|
23848fa728 | ||
|
|
0f21db1ecb | ||
|
|
08f6b6c93c | ||
|
|
1eab936618 | ||
|
|
d439c13fb5 | ||
|
|
4043f491da | ||
|
|
4b430b49a7 | ||
|
|
63c276d444 | ||
|
|
7dfa3bea18 | ||
|
|
33a0ae0fcd | ||
|
|
4273357adf | ||
|
|
132393cc64 | ||
|
|
ba9213234c | ||
|
|
498c4dddea | ||
|
|
439e158fb2 | ||
|
|
f0b7891d41 | ||
|
|
a03e9d340e | ||
|
|
06fd1f3c44 | ||
|
|
dec9fa0324 | ||
|
|
d9a9d50602 | ||
|
|
88447d69cb | ||
|
|
434018f679 | ||
|
|
115474b90f | ||
|
|
4dee108afe | ||
|
|
aa74ccf163 | ||
|
|
4c94d931fa | ||
|
|
569e7ac593 | ||
|
|
c7f147d058 | ||
|
|
47e77201d5 | ||
|
|
2d1b15b6fb | ||
|
|
04b64fa30c | ||
|
|
8f8db75bb4 | ||
|
|
95bc0813f8 | ||
|
|
9f8af1feea | ||
|
|
b86fe60a24 | ||
|
|
1f96ead801 | ||
|
|
b1a65e4c74 | ||
|
|
8e26d5257f | ||
|
|
cd4636a1e5 | ||
|
|
0f21595e4b | ||
|
|
b48b3b3237 | ||
|
|
0a586291b6 | ||
|
|
09b60e3f77 | ||
|
|
dffff77a5d | ||
|
|
ad3be8f8b5 | ||
|
|
1c0acee989 | ||
|
|
27e1462b00 | ||
|
|
d4500878cb | ||
|
|
af5fbef4ea | ||
|
|
d80891e823 | ||
|
|
2e3617adbb | ||
|
|
2804264289 | ||
|
|
cf18c2243f | ||
|
|
555b3f12ee | ||
|
|
211b58ac6e | ||
|
|
10aedaf0f4 | ||
|
|
999e1061b8 | ||
|
|
449d1f6ad2 | ||
|
|
33e9e660c4 | ||
|
|
3c96099f7c | ||
|
|
4edfd0d960 | ||
|
|
ecd56c6a40 | ||
|
|
b65460c12f | ||
|
|
496a21254b | ||
|
|
40574d31ac | ||
|
|
3a8cf68541 | ||
|
|
4cae0538a8 | ||
|
|
0638106bf3 | ||
|
|
0d86bdd216 | ||
|
|
2adacf74ac | ||
|
|
a8bd529871 | ||
|
|
61f157e89d | ||
|
|
b9f326bfa1 | ||
|
|
097ba45783 | ||
|
|
a539939388 | ||
|
|
ad821e83bd | ||
|
|
d6709b726e | ||
|
|
374cf517e1 | ||
|
|
3d98237304 | ||
|
|
49a4625368 | ||
|
|
12fc89f35d | ||
|
|
1d29c81346 | ||
|
|
7da424d53f | ||
|
|
e57b3651c2 | ||
|
|
615f9d3a1f | ||
|
|
eb8415a1f3 | ||
|
|
bcf29e6fbf | ||
|
|
82a2a705fb | ||
|
|
95061885b0 | ||
|
|
3e6f57b684 | ||
|
|
4f079d2768 | ||
|
|
d5aac7df25 | ||
|
|
9f51b12193 | ||
|
|
ed9e083008 | ||
|
|
e6cefba98b | ||
|
|
83a8b041ad | ||
|
|
2eb6c393a4 | ||
|
|
715410a9bc | ||
|
|
60a2151a33 | ||
|
|
0995f2700e | ||
|
|
59055e28ee | ||
|
|
4be5fcc14a | ||
|
|
180ae070ee | ||
|
|
594e2b6a77 | ||
|
|
ab5067a0d3 | ||
|
|
b10073465c | ||
|
|
05f278ce20 | ||
|
|
6d958eb32b | ||
|
|
b101550cae | ||
|
|
e51018406f | ||
|
|
036bfed984 | ||
|
|
fcdd5e0a19 | ||
|
|
aced2e7eb4 | ||
|
|
a2b0b3d6eb | ||
|
|
24c9b6e171 | ||
|
|
99af2a809b | ||
|
|
4d10b18fe1 | ||
|
|
87c055cc61 | ||
|
|
e5a28311bc | ||
|
|
f00ab135d6 | ||
|
|
3ec28f1242 | ||
|
|
b5dd2cc540 | ||
|
|
c6b9aebfcf | ||
|
|
afc0892d1f | ||
|
|
87ff70ee0f | ||
|
|
e6f6b0dad5 | ||
|
|
bf90cb5cc0 | ||
|
|
30dfd5cc1b | ||
|
|
a795a256f4 | ||
|
|
f56af41d1e | ||
|
|
23cbb83c75 | ||
|
|
1a4b9cb228 | ||
|
|
e4188f889e | ||
|
|
071744a57f | ||
|
|
eb9c775476 | ||
|
|
5e8cd654ec | ||
|
|
275cdbbea7 | ||
|
|
b1df91395a | ||
|
|
871d42f05a | ||
|
|
834cdd63ab | ||
|
|
505a6bcbf2 | ||
|
|
2e1b4cd692 | ||
|
|
2bb7bdfc3f | ||
|
|
ca46100581 | ||
|
|
c264a2e15f | ||
|
|
7c1249746f | ||
|
|
f63828ff20 | ||
|
|
f38753ee3c | ||
|
|
a63953432e | ||
|
|
52789df812 | ||
|
|
49c2f40f7d | ||
|
|
8842b6894e | ||
|
|
02721a0b7f | ||
|
|
496795dd56 | ||
|
|
a5d6541f1e | ||
|
|
a795313c7d | ||
|
|
bd53922c64 | ||
|
|
332a0f5adc | ||
|
|
0e4c3ec202 | ||
|
|
88a394e892 | ||
|
|
fa06965ed6 | ||
|
|
cf9d7a0470 | ||
|
|
040f5f88f2 | ||
|
|
5dc5ca551f | ||
|
|
ee36abd73a | ||
|
|
5c55b9fbbe | ||
|
|
ce434585e3 | ||
|
|
f8e5065845 | ||
|
|
f1c0d5316f | ||
|
|
eedcc19209 | ||
|
|
04591bb938 | ||
|
|
6d595e30c2 | ||
|
|
d62db8dc6b | ||
|
|
a645dc109a | ||
|
|
c73e58516b | ||
|
|
ab0d939626 | ||
|
|
feae5079ed | ||
|
|
ba185d7616 | ||
|
|
48cae0e480 | ||
|
|
8054020f61 | ||
|
|
d846d05527 | ||
|
|
d34b73befb | ||
|
|
d94da5af40 | ||
|
|
fa58f1b4d7 | ||
|
|
abf206a134 | ||
|
|
fee29c47c8 | ||
|
|
3e7357a5d7 | ||
|
|
daef8a0eed | ||
|
|
ed9e94c632 | ||
|
|
d01aaeb65c | ||
|
|
00e84fb483 | ||
|
|
22fb9ec5e1 | ||
|
|
15b063d236 | ||
|
|
dd2d9c1dc2 | ||
|
|
71161e218b | ||
|
|
0a0e628068 | ||
|
|
ac368ac182 | ||
|
|
955fe9e1e6 | ||
|
|
dbcd141a46 | ||
|
|
8794005234 | ||
|
|
bbe3b3cabe | ||
|
|
85420d1ffd | ||
|
|
1441aea2ea | ||
|
|
6924ddeace | ||
|
|
6f6a595fef | ||
|
|
d7c1993194 | ||
|
|
babb3b557d | ||
|
|
50d0f5bde6 | ||
|
|
91e8d9e211 | ||
|
|
e7753c31db | ||
|
|
38047240d3 | ||
|
|
5c4ba53f42 | ||
|
|
4906ddfc29 | ||
|
|
bbab0f11ca | ||
|
|
045a23ae10 | ||
|
|
b121bf8802 | ||
|
|
d0cc1635db | ||
|
|
1375267996 | ||
|
|
e37800d056 | ||
|
|
10ea2883f7 | ||
|
|
d58d75c6ef | ||
|
|
56201a6dc4 | ||
|
|
7a240b63c7 | ||
|
|
34e131c928 | ||
|
|
32826c1686 | ||
|
|
cf7048dd0f | ||
|
|
a879cb0cfd | ||
|
|
ac530ac49c | ||
|
|
f5d4dd33da | ||
|
|
573c6ab5d4 | ||
|
|
d2cd5d46fa | ||
|
|
dcc98e3839 | ||
|
|
78ffe47bf8 | ||
|
|
bd88919411 | ||
|
|
465a424af4 | ||
|
|
b8ebc087e2 | ||
|
|
087551ad61 | ||
|
|
b8563f7fcf | ||
|
|
cab80812ef | ||
|
|
631f58f27f | ||
|
|
2c692de98f | ||
|
|
19db4869e6 | ||
|
|
b6974a88c5 | ||
|
|
3a14a5c461 | ||
|
|
831467891c | ||
|
|
f6734e74e1 | ||
|
|
23698f93e0 | ||
|
|
6b6d7a5030 | ||
|
|
e8749e639c | ||
|
|
8c91dc579a | ||
|
|
9bbea47f93 | ||
|
|
e5a128ab2e | ||
|
|
73b879ea89 | ||
|
|
e037e9de39 | ||
|
|
8d1d76cdae | ||
|
|
da53317357 | ||
|
|
0568bc3ef1 | ||
|
|
fd80c0d1d1 | ||
|
|
05ef705609 | ||
|
|
006062499c | ||
|
|
774aa720b4 | ||
|
|
a0a8beee82 | ||
|
|
ce3b455f57 | ||
|
|
c46164481a | ||
|
|
a087ea559f | ||
|
|
ec403bfdbc | ||
|
|
3c09a26e16 | ||
|
|
3fc106572e | ||
|
|
eda43c8b45 | ||
|
|
29e5ad5abe | ||
|
|
8a3fa2e4e5 | ||
|
|
a5e4e0284e | ||
|
|
d21d362f0f | ||
|
|
39055229a1 | ||
|
|
830bf62d94 | ||
|
|
4e98394c38 | ||
|
|
688802de51 | ||
|
|
e6ee933b27 | ||
|
|
6d9b519bb2 | ||
|
|
0a7a73d4be | ||
|
|
9120ccc054 | ||
|
|
d886cd7d06 | ||
|
|
2719016539 | ||
|
|
b240ae791c | ||
|
|
52d11eb22b | ||
|
|
82d7a269ed | ||
|
|
394c68c326 | ||
|
|
530214fcee | ||
|
|
be90f7d331 | ||
|
|
2b21280ba9 | ||
|
|
8761ef6694 | ||
|
|
7173e56393 | ||
|
|
f2fea9a04a | ||
|
|
5e80d80797 | ||
|
|
32bdb6becb | ||
|
|
faa0dff649 | ||
|
|
cc20c66bfc | ||
|
|
e8640b441d | ||
|
|
811b8978c2 | ||
|
|
c5ee28da05 | ||
|
|
26537cd8fc | ||
|
|
0e583aa929 | ||
|
|
278cc71c4a | ||
|
|
641a9a7153 | ||
|
|
19ea18a340 | ||
|
|
01a9d9a284 | ||
|
|
8c3936a0ee | ||
|
|
3bf7223448 | ||
|
|
27bf51c73f | ||
|
|
6a68eb218f | ||
|
|
c9df227fef | ||
|
|
73a2c8c436 | ||
|
|
5d461ec6df | ||
|
|
4261880340 | ||
|
|
999ef51653 | ||
|
|
cbccb68948 | ||
|
|
9f2ce3c521 | ||
|
|
d188de3086 | ||
|
|
5e8afd26e1 | ||
|
|
f950ff4b8f | ||
|
|
9a2c9ed30e | ||
|
|
954c1d853d | ||
|
|
a2f7808ab1 | ||
|
|
263cf85c5c | ||
|
|
11caa03427 | ||
|
|
80063b6f91 | ||
|
|
b83b534374 | ||
|
|
c038d3e9a3 | ||
|
|
646f50dd66 | ||
|
|
1296c5444b | ||
|
|
61e8848aa2 | ||
|
|
a04e6de047 | ||
|
|
75ae42121b | ||
|
|
578dd1dc42 | ||
|
|
d096f1d381 | ||
|
|
cb61c358ea | ||
|
|
1bbbc1ca1c | ||
|
|
68fab55251 | ||
|
|
6bc6c1b6cc | ||
|
|
4ba8268a29 | ||
|
|
e4683a1e9f | ||
|
|
8c32719f3d | ||
|
|
b3aeddac85 | ||
|
|
8e8f83656f | ||
|
|
ee6aae7219 | ||
|
|
ef38761dc2 | ||
|
|
a6ca2906d8 | ||
|
|
723c9be5a0 | ||
|
|
8567db10b5 | ||
|
|
18fb70b32f | ||
|
|
268f7b715c | ||
|
|
50e7973fc0 | ||
|
|
243f718193 | ||
|
|
4637dcde33 | ||
|
|
ff9fe85507 | ||
|
|
5e4459f41d | ||
|
|
0111c4d581 | ||
|
|
7c22113c34 | ||
|
|
c952e26cbb | ||
|
|
1bad04db50 | ||
|
|
e3391175d9 | ||
|
|
4c6b9b695c | ||
|
|
fcffd190d0 | ||
|
|
73e94ffde0 | ||
|
|
6605ba80e7 | ||
|
|
0432e2e947 | ||
|
|
d9710ea4ff | ||
|
|
8965bb8977 | ||
|
|
1376c8f8cf | ||
|
|
a907ec92b5 | ||
|
|
39010ab847 | ||
|
|
25c1828288 | ||
|
|
de8dd37e44 | ||
|
|
f120865350 | ||
|
|
297eb952bc | ||
|
|
b52b90c182 | ||
|
|
4e91dadfab | ||
|
|
bafa0ec1ee | ||
|
|
5a00a97cf1 | ||
|
|
3cb8f1ab20 | ||
|
|
a36e457c12 | ||
|
|
2b1b1fb0d4 | ||
|
|
abb5bc6aba | ||
|
|
ee0874a26d | ||
|
|
67699bf17e | ||
|
|
57877bb007 | ||
|
|
a03ed6f742 | ||
|
|
ffe3453937 | ||
|
|
3060ecc066 | ||
|
|
634d9834de | ||
|
|
d573962259 | ||
|
|
e2dcec62d3 | ||
|
|
0e5603f644 | ||
|
|
c2e5fc5215 | ||
|
|
39d0cd7237 | ||
|
|
6fb83c2ba3 | ||
|
|
415c3d57af | ||
|
|
9e5ecc11b7 | ||
|
|
f636ab21f8 | ||
|
|
97fbbc74e6 | ||
|
|
dc1d92855d | ||
|
|
c92f118e5e | ||
|
|
9baaf607a3 | ||
|
|
c226707a80 | ||
|
|
ab3681e164 | ||
|
|
3ef612f05a | ||
|
|
6dd75f697a | ||
|
|
593fbadc98 | ||
|
|
060095d39f | ||
|
|
2506bb6673 | ||
|
|
af7de9a0c5 | ||
|
|
000da2f6d0 | ||
|
|
78b4cbdb69 | ||
|
|
0c0e0aab09 | ||
|
|
322379e6ae | ||
|
|
1d86bd5610 | ||
|
|
adc937c57d | ||
|
|
8d425a6f94 | ||
|
|
4d47c0fd63 | ||
|
|
3ad4f18e1a | ||
|
|
875fdef917 | ||
|
|
318014e4ab | ||
|
|
91cd590395 | ||
|
|
a7fc32c8da | ||
|
|
1e0ae04aba | ||
|
|
b5a8ffaddc | ||
|
|
dd61a5b2c6 | ||
|
|
63b16e14d8 | ||
|
|
885f397cdd | ||
|
|
6046b25f56 | ||
|
|
045a12ddc6 | ||
|
|
e66c2621af | ||
|
|
d0134f2c64 | ||
|
|
e2e57e5b6d | ||
|
|
0f1f354ba6 | ||
|
|
abbbdb5771 | ||
|
|
559da842c0 | ||
|
|
e19c1b5364 | ||
|
|
12b48f86e7 | ||
|
|
794cc1e3be | ||
|
|
86994f81c3 | ||
|
|
21de67cac1 | ||
|
|
387c91f957 | ||
|
|
6608e97d35 | ||
|
|
2d9392aad4 | ||
|
|
6ed3672f8d | ||
|
|
ecec87cbc7 | ||
|
|
9e03b712de | ||
|
|
14dad61fe5 | ||
|
|
90c2b14051 | ||
|
|
b9b4cce293 | ||
|
|
266d7c15fe | ||
|
|
f0be88fc07 | ||
|
|
dffbe0f707 | ||
|
|
cd92e3fc98 | ||
|
|
fa5728b288 | ||
|
|
00e8dfe1be | ||
|
|
4202bde550 | ||
|
|
c7a2422314 | ||
|
|
6d9ecc60ef | ||
|
|
a16f412b48 | ||
|
|
1ae95853e7 | ||
|
|
d3682b7f7d | ||
|
|
63aae56b11 | ||
|
|
a3a782613a | ||
|
|
1032f0d39c | ||
|
|
b9469a9308 | ||
|
|
75234701c7 | ||
|
|
b23911fd59 | ||
|
|
7b2ea001c1 | ||
|
|
c5bc58ad32 | ||
|
|
f9dedab8c8 | ||
|
|
3eb5b3e08c | ||
|
|
5c9f0df256 | ||
|
|
6b62686019 | ||
|
|
bc90d52873 | ||
|
|
6a4590839c | ||
|
|
20f92c6200 | ||
|
|
5ed5f8f048 | ||
|
|
a9678010a8 | ||
|
|
e3dab96715 | ||
|
|
6e8f227121 | ||
|
|
b393c66426 | ||
|
|
c0c01d6e49 | ||
|
|
8e951dee16 | ||
|
|
eebb820060 | ||
|
|
3cea5c4510 | ||
|
|
5867d27fb7 | ||
|
|
d124912c91 | ||
|
|
909d83c3af | ||
|
|
66f5a12cc4 | ||
|
|
c6bfb02754 | ||
|
|
0a24bf1613 | ||
|
|
81df7645e0 | ||
|
|
d24ebf711b | ||
|
|
a8625b632d | ||
|
|
85f9e2e47b | ||
|
|
378acbf7ec | ||
|
|
21449763ab | ||
|
|
103bd6dbde | ||
|
|
d499998655 | ||
|
|
4b31e75550 | ||
|
|
ee1152bc98 | ||
|
|
f2aacf774e | ||
|
|
1bb7a617ad | ||
|
|
a3baca829f | ||
|
|
d1b17f050b | ||
|
|
5b9b003e02 | ||
|
|
86d1c7b7ec | ||
|
|
3b222f13f3 | ||
|
|
b2de822fd4 | ||
|
|
0d8f64353a | ||
|
|
83d64e8eba | ||
|
|
7bae72113b | ||
|
|
f7391f6c1a | ||
|
|
d58707972d | ||
|
|
e16b0524b6 | ||
|
|
dfb60ba4ac | ||
|
|
62a15e803b | ||
|
|
6e0f3b7f1f | ||
|
|
667c00e3ed | ||
|
|
3225c93ce0 | ||
|
|
797813a8d4 | ||
|
|
6aa3c26f78 | ||
|
|
58713270bb | ||
|
|
de2117663c | ||
|
|
9d11f0b92f | ||
|
|
1ee2053a16 | ||
|
|
4d451356eb | ||
|
|
ea228a2fa8 | ||
|
|
612481f0f4 | ||
|
|
cdeabf26b4 | ||
|
|
4d4e2c5c94 | ||
|
|
8e407d548a | ||
|
|
71fcb07fad | ||
|
|
b56639a775 | ||
|
|
8457ab7c58 | ||
|
|
ba84338862 | ||
|
|
bae955aafd | ||
|
|
46bd64f59a | ||
|
|
41f7950ab8 | ||
|
|
4c808e8691 | ||
|
|
a903c4ab0e | ||
|
|
7704310359 | ||
|
|
3bc322c2ce | ||
|
|
f06d46fe9a | ||
|
|
8e9536f61d | ||
|
|
35b41b9401 | ||
|
|
95bfe8668d | ||
|
|
5d65e6bc9b | ||
|
|
2e01f62afe | ||
|
|
0d2122bb1d | ||
|
|
2790fcf4bd | ||
|
|
060a865fb1 | ||
|
|
4b7380bea4 | ||
|
|
8e3cb912c7 | ||
|
|
c10524586a | ||
|
|
2e8bfde2e7 | ||
|
|
a1a71a01b1 | ||
|
|
e1463f9e0f | ||
|
|
5515a63911 | ||
|
|
8c84717cbc | ||
|
|
a2e429a912 | ||
|
|
b6fa10cf9e | ||
|
|
be0211cd49 | ||
|
|
2490318f93 | ||
|
|
fee676a281 | ||
|
|
9e1afe71f2 | ||
|
|
ad313750e7 | ||
|
|
1452d7e4a6 | ||
|
|
75c56d58ae | ||
|
|
add16dec3d | ||
|
|
574a0e629e | ||
|
|
7fbca4e122 | ||
|
|
330beebb2c | ||
|
|
9397b16bb9 | ||
|
|
407815449a | ||
|
|
57f2feb6fb | ||
|
|
6793861fd4 | ||
|
|
20d856fa77 | ||
|
|
8fee62a8c5 | ||
|
|
4c9afb9d20 | ||
|
|
3efda0e45a | ||
|
|
9eae929084 | ||
|
|
39d204c550 | ||
|
|
cb7de0e262 | ||
|
|
ebf9e386b0 | ||
|
|
7192529733 | ||
|
|
82320bdf7d | ||
|
|
46894da981 | ||
|
|
f6fd9441e9 | ||
|
|
20dc1a047d | ||
|
|
5f843f6759 | ||
|
|
fcb4db0226 | ||
|
|
1f179a6f01 | ||
|
|
b989bfce59 | ||
|
|
dd275eda78 | ||
|
|
87187437ab | ||
|
|
da2f310895 |
2
.idea/ant.xml
generated
2
.idea/ant.xml
generated
@@ -3,7 +3,7 @@
|
||||
<component name="AntConfiguration">
|
||||
<buildFile url="file://$PROJECT_DIR$/compiler/frontend/buildLexer.xml" />
|
||||
<buildFile url="file://$PROJECT_DIR$/build.xml">
|
||||
<antCommandLine value="-J-XX:MaxPermSize=100m -J-ea" />
|
||||
<antCommandLine value="-J-ea" />
|
||||
<maximumHeapSize value="1024" />
|
||||
</buildFile>
|
||||
<buildFile url="file://$PROJECT_DIR$/update_dependencies.xml" />
|
||||
|
||||
1
.idea/artifacts/KotlinJpsPlugin.xml
generated
1
.idea/artifacts/KotlinJpsPlugin.xml
generated
@@ -11,7 +11,6 @@
|
||||
<element id="directory" name="META-INF">
|
||||
<element id="dir-copy" path="$PROJECT_DIR$/jps-plugin/src/META-INF" />
|
||||
</element>
|
||||
<element id="extracted-dir" path="$PROJECT_DIR$/dependencies/cli-parser-1.1.2.jar" path-in-jar="/" />
|
||||
<element id="module-output" name="cli-common" />
|
||||
<element id="module-output" name="idea-jps-common" />
|
||||
<element id="module-output" name="jps-plugin" />
|
||||
|
||||
7
.idea/dictionaries/4u7.xml
generated
Normal file
7
.idea/dictionaries/4u7.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="4u7">
|
||||
<words>
|
||||
<w>foldable</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
||||
10
.idea/inspectionProfiles/idea_default.xml
generated
10
.idea/inspectionProfiles/idea_default.xml
generated
@@ -1,7 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0" is_locked="false">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="idea.default" />
|
||||
<option name="myLocal" value="false" />
|
||||
<inspection_tool class="AbstractMethodCallInConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="ArchaicSystemPropertyAccess" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="AssignmentToForLoopParameter" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
@@ -236,10 +235,6 @@
|
||||
<scope name="idea openapi" level="WARNING" enabled="true" />
|
||||
<scope name="runtime.classes" level="ERROR" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="LoggerInitializedWithForeignClass" enabled="false" level="WARNING" enabled_by_default="false">
|
||||
<option name="loggerClassName" value="org.apache.log4j.Logger,org.slf4j.LoggerFactory,org.apache.commons.logging.LogFactory,java.util.logging.Logger" />
|
||||
<option name="loggerFactoryMethodName" value="getLogger,getLogger,getLog,getLogger" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="LoopToCallChain" enabled="false" level="INFO" enabled_by_default="false" />
|
||||
<inspection_tool class="MethodMayBeStatic" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="m_onlyPrivateOrFinal" value="false" />
|
||||
@@ -347,11 +342,12 @@
|
||||
<constraint name="__context__" script="""" within="" contains="" />
|
||||
</searchConfiguration>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SameParameterValue" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SetReplaceableByEnumSet" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SetupCallsSuperSetup" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SetupIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SimplifiableIfStatement" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="Since15" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<inspection_tool class="Since15" enabled="false" level="ERROR" enabled_by_default="false">
|
||||
<scope name="IDEA Test Sources" level="ERROR" enabled="false" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SocketResource" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
|
||||
4
.idea/kotlinc.xml
generated
4
.idea/kotlinc.xml
generated
@@ -1,5 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KotlinCommonCompilerArguments">
|
||||
<option name="languageVersion" value="1.1" />
|
||||
<option name="apiVersion" value="1.1" />
|
||||
</component>
|
||||
<component name="KotlinCompilerSettings">
|
||||
<option name="additionalArguments" value="-version -Xallow-kotlin-package -Xskip-metadata-version-check" />
|
||||
</component>
|
||||
|
||||
11
.idea/libraries/cli_parser.xml
generated
11
.idea/libraries/cli_parser.xml
generated
@@ -1,11 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="cli-parser">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/cli-parser-1.1.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/cli-parser-1.1.2-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
4
.idea/libraries/guava.xml
generated
4
.idea/libraries/guava.xml
generated
@@ -4,11 +4,11 @@
|
||||
<root url="file://$PROJECT_DIR$/annotations" />
|
||||
</ANNOTATIONS>
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/lib/guava-17.0.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/lib/guava-19.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/guava-17.0-sources.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/guava-19.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
2
.idea/libraries/idea_full.xml
generated
2
.idea/libraries/idea_full.xml
generated
@@ -9,7 +9,7 @@
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/guava-17.0-sources.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/guava-19.0-sources.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/asm5-src.zip!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/sources/sources.jar!/" />
|
||||
</SOURCES>
|
||||
|
||||
2
.idea/libraries/intellij_core.xml
generated
2
.idea/libraries/intellij_core.xml
generated
@@ -9,7 +9,7 @@
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/guava-17.0-sources.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/guava-19.0-sources.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/asm5-src.zip!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/sources/sources.jar!/" />
|
||||
</SOURCES>
|
||||
|
||||
2
.idea/libraries/intellij_core_analysis.xml
generated
2
.idea/libraries/intellij_core_analysis.xml
generated
@@ -10,7 +10,7 @@
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/asm5-src.zip!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/guava-17.0-sources.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/guava-19.0-sources.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/sources/sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
|
||||
1
.idea/libraries/properties.xml
generated
1
.idea/libraries/properties.xml
generated
@@ -5,6 +5,7 @@
|
||||
</ANNOTATIONS>
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/properties/lib/properties.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/properties/lib/resources_en.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
|
||||
3
.idea/misc.xml
generated
3
.idea/misc.xml
generated
@@ -6,7 +6,6 @@
|
||||
</properties>
|
||||
</component>
|
||||
<component name="EntryPointsManager">
|
||||
<entry_points version="2.0" />
|
||||
<list size="1">
|
||||
<item index="0" class="java.lang.String" itemvalue="javax.inject.Inject" />
|
||||
</list>
|
||||
@@ -49,7 +48,7 @@
|
||||
<component name="ProjectResources">
|
||||
<default-html-doctype>http://www.w3.org/1999/xhtml</default-html-doctype>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" default="false" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
<component name="SuppressABINotification">
|
||||
|
||||
1
.idea/modules.xml
generated
1
.idea/modules.xml
generated
@@ -92,6 +92,7 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/sam-with-receiver/sam-with-receiver-ide/sam-with-receiver-ide.iml" filepath="$PROJECT_DIR$/plugins/sam-with-receiver/sam-with-receiver-ide/sam-with-receiver-ide.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/core/script.runtime/script.runtime.iml" filepath="$PROJECT_DIR$/core/script.runtime/script.runtime.iml" group="core" />
|
||||
<module fileurl="file://$PROJECT_DIR$/compiler/serialization/serialization.iml" filepath="$PROJECT_DIR$/compiler/serialization/serialization.iml" group="compiler" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/source-sections/source-sections-compiler/source-sections-compiler.iml" filepath="$PROJECT_DIR$/plugins/source-sections/source-sections-compiler/source-sections-compiler.iml" group="plugins" />
|
||||
<module fileurl="file://$PROJECT_DIR$/compiler/tests-common/tests-common.iml" filepath="$PROJECT_DIR$/compiler/tests-common/tests-common.iml" group="compiler" />
|
||||
<module fileurl="file://$PROJECT_DIR$/compiler/tests-ir-jvm/tests-ir-jvm.iml" filepath="$PROJECT_DIR$/compiler/tests-ir-jvm/tests-ir-jvm.iml" group="compiler/ir" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/uast-kotlin/uast-kotlin.iml" filepath="$PROJECT_DIR$/plugins/uast-kotlin/uast-kotlin.iml" group="plugins/lint" />
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<option name="MAIN_CLASS_NAME" value="" />
|
||||
<option name="METHOD_NAME" value="" />
|
||||
<option name="TEST_OBJECT" value="package" />
|
||||
<option name="VM_PARAMETERS" value="-ea -XX:+HeapDumpOnOutOfMemoryError -Xmx900m -XX:MaxPermSize=320m -XX:+UseCodeCacheFlushing -XX:ReservedCodeCacheSize=64m -Djna.nosys=true" />
|
||||
<option name="VM_PARAMETERS" value="-ea -XX:+HeapDumpOnOutOfMemoryError -Xmx1024m -XX:+UseCodeCacheFlushing -XX:ReservedCodeCacheSize=64m -Djna.nosys=true" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<option name="MAIN_CLASS_NAME" value="" />
|
||||
<option name="METHOD_NAME" value="" />
|
||||
<option name="TEST_OBJECT" value="package" />
|
||||
<option name="VM_PARAMETERS" value="-ea -XX:+HeapDumpOnOutOfMemoryError -Xmx1100m -XX:+UseCodeCacheFlushing -XX:ReservedCodeCacheSize=128m -Djna.nosys=true" />
|
||||
<option name="VM_PARAMETERS" value="-ea -XX:+HeapDumpOnOutOfMemoryError -Xmx900m -XX:+UseCodeCacheFlushing -XX:ReservedCodeCacheSize=128m -Djna.nosys=true" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
|
||||
2
.idea/runConfigurations/Compiler_Tests.xml
generated
2
.idea/runConfigurations/Compiler_Tests.xml
generated
@@ -13,7 +13,7 @@
|
||||
<option name="MAIN_CLASS_NAME" value="" />
|
||||
<option name="METHOD_NAME" value="" />
|
||||
<option name="TEST_OBJECT" value="package" />
|
||||
<option name="VM_PARAMETERS" value="-ea -XX:+HeapDumpOnOutOfMemoryError -Xmx700m -XX:MaxPermSize=300m -XX:+UseCodeCacheFlushing -XX:ReservedCodeCacheSize=64m -Djna.nosys=true" />
|
||||
<option name="VM_PARAMETERS" value="-ea -XX:+HeapDumpOnOutOfMemoryError -Xmx1024m -XX:+UseCodeCacheFlushing -XX:ReservedCodeCacheSize=64m -Djna.nosys=true" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
|
||||
159
ChangeLog.md
159
ChangeLog.md
@@ -3,6 +3,165 @@
|
||||
<!-- Find: ([^\`/\[])(KT-\d+) -->
|
||||
<!-- Replace: $1[`$2`](https://youtrack.jetbrains.com/issue/$2) -->
|
||||
|
||||
## 1.1.1
|
||||
|
||||
### IDE
|
||||
- [`KT-16714`](https://youtrack.jetbrains.com/issue/KT-16714) J2K: Write access is allowed from event dispatch thread only
|
||||
|
||||
### Compiler
|
||||
- [`KT-16801`](https://youtrack.jetbrains.com/issue/KT-16801) Accessors of `@PublishedApi` property gets mangled
|
||||
- [`KT-16673`](https://youtrack.jetbrains.com/issue/KT-16673) Potentially problematic code causes exception when work with SAM adapters
|
||||
|
||||
### Libraries
|
||||
- [`KT-16557`](https://youtrack.jetbrains.com/issue/KT-16557) Correct `SinceKotlin(1.1)` for all declarations in `kotlin.reflect.full`
|
||||
|
||||
## 1.1.1-RC
|
||||
|
||||
### IDE
|
||||
- [`KT-16481`](https://youtrack.jetbrains.com/issue/KT-16481) Kotlin debugger & bytecode fail on select statement blocks (IllegalStateException: More than one package fragment)
|
||||
|
||||
### Gradle support
|
||||
- [`KT-15783`](https://youtrack.jetbrains.com/issue/KT-15783) Gradle builds don't use incremental compilation due to an error: "Could not connect to kotlin daemon"
|
||||
- [`KT-16434`](https://youtrack.jetbrains.com/issue/KT-16434) Gradle plugin does not compile androidTest sources when Jack is enabled
|
||||
- [`KT-16546`](https://youtrack.jetbrains.com/issue/KT-16546) Enable incremental compilation in gradle by default
|
||||
|
||||
### Compiler
|
||||
- [`KT-16184`](https://youtrack.jetbrains.com/issue/KT-16184) AbstractMethodError in Kapt3ComponentRegistrar while compiling from IntelliJ using Kotlin 1.1.0
|
||||
- [`KT-16578`](https://youtrack.jetbrains.com/issue/KT-16578) Fix substitutor for synthetic SAM adapters
|
||||
- [`KT-16581`](https://youtrack.jetbrains.com/issue/KT-16581) VerifyError when calling default value parameter with jvm-target 1.8
|
||||
- [`KT-16583`](https://youtrack.jetbrains.com/issue/KT-16583) Cannot access private file-level variables inside a class init within the same file if a secondary constructor is present
|
||||
- [`KT-16587`](https://youtrack.jetbrains.com/issue/KT-16587) AbstractMethodError: Delegates not generated correctly for private interfaces
|
||||
- [`KT-16598`](https://youtrack.jetbrains.com/issue/KT-16598) Incorrect error: The feature "bound callable references" is only available since language version 1.1
|
||||
- [`KT-16621`](https://youtrack.jetbrains.com/issue/KT-16621) Kotlin compiler doesn't report an error if a class implements Annotation interface but doesn't implement annotationType method
|
||||
- [`KT-16441`](https://youtrack.jetbrains.com/issue/KT-16441) `NoSuchFieldError: $$delegatedProperties` when delegating through `provideDelegate` in companion object
|
||||
|
||||
### JavaScript support
|
||||
- Prohibit function types with receiver as parameter types of external declarations
|
||||
- Remove extension receiver for function parameters in `jQuery` declarations
|
||||
|
||||
## 1.1
|
||||
|
||||
### Compiler exceptions
|
||||
- [`KT-16411`](https://youtrack.jetbrains.com/issue/KT-16411) Exception from compiler when try to inline callable reference to class constructor inside object
|
||||
- [`KT-16412`](https://youtrack.jetbrains.com/issue/KT-16412) Exception from compiler when try call SAM constructor where argument is callable reference to nested class inside object
|
||||
- [`KT-16413`](https://youtrack.jetbrains.com/issue/KT-16413) When we create sam adapter for java.util.function.Function we add incorrect null-check for argument
|
||||
|
||||
### Standard library
|
||||
- [`KT-6561`](https://youtrack.jetbrains.com/issue/KT-6561) Drop java.util.Collections package from js stdlib
|
||||
- `javaClass` extension property is no more deprecated due to migration problems
|
||||
|
||||
### IDE
|
||||
- [`KT-16329`](https://youtrack.jetbrains.com/issue/KT-16329) Inspection "Calls to staic methods in Java interfaces..." always reports warning undependent of jvm-target
|
||||
|
||||
|
||||
## 1.1-RC
|
||||
|
||||
### Reflection
|
||||
- [`KT-16358`](https://youtrack.jetbrains.com/issue/KT-16358) Incompatibility between kotlin-reflect 1.0 and kotlin-stdlib 1.1 fixed
|
||||
|
||||
### Compiler
|
||||
|
||||
#### Coroutine support
|
||||
- [`KT-15938`](https://youtrack.jetbrains.com/issue/KT-15938) Changed error message for calling suspend function outside of suspendable context
|
||||
- [`KT-16092`](https://youtrack.jetbrains.com/issue/KT-16092) Backend crash fixed: "Don't know how to generate outer expression" for destructuring suspend lambda
|
||||
- [`KT-16093`](https://youtrack.jetbrains.com/issue/KT-16093) Annotations are retained during reading the binary representation of suspend functions
|
||||
- [`KT-16122`](https://youtrack.jetbrains.com/issue/KT-16122) java.lang.VerifyError fixed in couroutines: (String, null, suspend () -> String)
|
||||
- [`KT-16124`](https://youtrack.jetbrains.com/issue/KT-16124) Marked as UNSUPPORTED: suspension points in default parameters
|
||||
- [`KT-16219`](https://youtrack.jetbrains.com/issue/KT-16219) Marked as UNSUPPORTED: suspend get/set, in/!in operators for
|
||||
- [`KT-16145`](https://youtrack.jetbrains.com/issue/KT-16145) Beta-2 coroutine regression fixed (wrong code generation)
|
||||
|
||||
#### Kapt3
|
||||
- [`KT-15524`](https://youtrack.jetbrains.com/issue/KT-15524) Fix javac error reporting in Kotlin daemon
|
||||
- [`KT-15721`](https://youtrack.jetbrains.com/issue/KT-15721) JetBrains nullability annotations are now returned from Element.getAnnotationMirrors()
|
||||
- [`KT-16146`](https://youtrack.jetbrains.com/issue/KT-16146) Fixed work in verbose mode
|
||||
- [`KT-16153`](https://youtrack.jetbrains.com/issue/KT-16153) Ignore declarations with illegal Java identifiers
|
||||
- [`KT-16167`](https://youtrack.jetbrains.com/issue/KT-16167) Fixed compilation error with kapt arguments in build.gradle
|
||||
- [`KT-16170`](https://youtrack.jetbrains.com/issue/KT-16170) Stub generator now adds imports for corrected error types to stubs
|
||||
- [`KT-16176`](https://youtrack.jetbrains.com/issue/KT-16176) javac's finalCompiler log is now used to determine annotation processing errors
|
||||
|
||||
#### Backward compatibility
|
||||
- [`KT-16017`](https://youtrack.jetbrains.com/issue/KT-16017) More graceful error message for disabled features
|
||||
- [`KT-16073`](https://youtrack.jetbrains.com/issue/KT-16073) Improved backward compatibility mode with version 1.0 on JDK dependent built-ins
|
||||
- [`KT-16094`](https://youtrack.jetbrains.com/issue/KT-16094) Compiler considers API availability when compiling language features requiring runtime support
|
||||
- [`KT-16171`](https://youtrack.jetbrains.com/issue/KT-16171) Fixed regression "Unexpected container error on Kotlin 1.0 project"
|
||||
- [`KT-16199`](https://youtrack.jetbrains.com/issue/KT-16199) Do not import "kotlin.comparisons.*" by default in language version 1.0 mode
|
||||
|
||||
#### Various issues
|
||||
- [`KT-16225`](https://youtrack.jetbrains.com/issue/KT-16225) enumValues non-reified stub implementation references nonexistent method no more
|
||||
- [`KT-16291`](https://youtrack.jetbrains.com/issue/KT-16291) Smart cast works now when getting class of instance
|
||||
- [`KT-16380`](https://youtrack.jetbrains.com/issue/KT-16380) Show warning when running the compiler under Java 6 or 7
|
||||
|
||||
### JavaScript backend
|
||||
- [`KT-16144`](https://youtrack.jetbrains.com/issue/KT-16144) Fixed inlining of functions called through inheritor ("fake" override) from another module
|
||||
- [`KT-16158`](https://youtrack.jetbrains.com/issue/KT-16158) Error is not reported now when library path contains JAR file without JS metadata, report warning instead
|
||||
- [`KT-16160`](https://youtrack.jetbrains.com/issue/KT-16160) Companion object dispatch receiver translation fixed
|
||||
|
||||
### Standard library
|
||||
- [`KT-7858`](https://youtrack.jetbrains.com/issue/KT-7858) Add extension function `takeUnless`
|
||||
- `javaClass` extension property is deprecated, use `instance::class.java` instead
|
||||
- Massive deprecations are coming in JS standard library in `kotlin.dom` and `kotlin.dom.build` packages
|
||||
|
||||
### IDE
|
||||
|
||||
#### Configuration issues
|
||||
- [`KT-15899`](https://youtrack.jetbrains.com/issue/KT-15899) Kotlin facet: language and api version for submodule setup for 1.0 are filled now as 1.0 too
|
||||
- [`KT-15914`](https://youtrack.jetbrains.com/issue/KT-15914) Kotlin facet works now with multi-selected modules in Project Settings too
|
||||
- [`KT-15954`](https://youtrack.jetbrains.com/issue/KT-15954) Does not suggest to configure kotlin for the module after each new kt-file creation
|
||||
- [`KT-16157`](https://youtrack.jetbrains.com/issue/KT-16157) freeCompilerArgs are now imported from Gradle into IDEA
|
||||
- [`KT-16206`](https://youtrack.jetbrains.com/issue/KT-16206) Idea no more refuses to compile a kotlin project defined as a maven project
|
||||
- [`KT-16312`](https://youtrack.jetbrains.com/issue/KT-16312) Kotlin facet: import from gradle: don't import options which are set implicitly already
|
||||
- [`KT-16325`](https://youtrack.jetbrains.com/issue/KT-16325) Kotlin facet: correct configuration after upgrading the IDE plugin
|
||||
- [`KT-16345`](https://youtrack.jetbrains.com/issue/KT-16345) Kotlin facet: detect JavaScript if the module has language 1.0 `kotlin-js-library` dependency
|
||||
|
||||
#### Coroutine support
|
||||
- [`KT-16109`](https://youtrack.jetbrains.com/issue/KT-16109) Error fixed: The -Xcoroutines can only have one value
|
||||
- [`KT-16251`](https://youtrack.jetbrains.com/issue/KT-16251) Fix detection of suspend calls containing extracted parameters
|
||||
|
||||
#### Intention actions, inspections and quick-fixes
|
||||
|
||||
##### 2017.1 compatibility
|
||||
- [`KT-15870`](https://youtrack.jetbrains.com/issue/KT-15870) "Package name does not match containing directory" inspection: fixed throwable "AWT events are not allowed inside write action"
|
||||
- [`KT-15924`](https://youtrack.jetbrains.com/issue/KT-15924) Create Test action: fixed throwable "AWT events are not allowed inside write action"
|
||||
|
||||
##### Bug fixes
|
||||
- [`KT-14831`](https://youtrack.jetbrains.com/issue/KT-14831) Import statement and FQN are not added on converting lambda to reference for typealias
|
||||
- [`KT-15545`](https://youtrack.jetbrains.com/issue/KT-15545) Inspection "join with assignment" does not change now execution order for properties
|
||||
- [`KT-15744`](https://youtrack.jetbrains.com/issue/KT-15744) Fix: intention to import `sleep` wrongly suggests `Thread.sleep`
|
||||
- [`KT-16000`](https://youtrack.jetbrains.com/issue/KT-16000) Inspection "join with assignment" handles initialization with 'this' correctly
|
||||
- [`KT-16009`](https://youtrack.jetbrains.com/issue/KT-16009) Auto-import for JDK classes in .kts files
|
||||
- [`KT-16104`](https://youtrack.jetbrains.com/issue/KT-16104) Don't insert modifiers (e.g. suspend) before visibility
|
||||
|
||||
#### Completion
|
||||
- [`KT-16076`](https://youtrack.jetbrains.com/issue/KT-16076) Completion does not insert more FQN kotlin.text.String
|
||||
- [`KT-16088`](https://youtrack.jetbrains.com/issue/KT-16088) Completion does not insert more FQN for `kotlin` package
|
||||
- [`KT-16110`](https://youtrack.jetbrains.com/issue/KT-16110) Keyword 'suspend' completion inside generic arguments
|
||||
- [`KT-16243`](https://youtrack.jetbrains.com/issue/KT-16243) Performance enhanced after variable of type `ArrayList`
|
||||
|
||||
#### Various issues
|
||||
- [`KT-15291`](https://youtrack.jetbrains.com/issue/KT-15291) 'Find usages' now does not report property access as usage of getter method in Java class with parameter
|
||||
- [`KT-15647`](https://youtrack.jetbrains.com/issue/KT-15647) Exception fixed: KDoc link to member of class from different package and module
|
||||
- [`KT-16071`](https://youtrack.jetbrains.com/issue/KT-16071) IDEA deadlock fixed: when typing "parse()" in .kt file
|
||||
- [`KT-16149`](https://youtrack.jetbrains.com/issue/KT-16149) Intellij Idea 2017.1/Android Studio 2.3 beta3 and Kotlin plugin 1.1-beta2 deadlock fixed
|
||||
|
||||
### Coroutine libraries
|
||||
- [`KT-15716`](https://youtrack.jetbrains.com/issue/KT-15716) Introduced startCoroutineUninterceptedOrReturn coroutine intrinsic
|
||||
- [`KT-15718`](https://youtrack.jetbrains.com/issue/KT-15718) createCoroutine now returns safe continuation
|
||||
- [`KT-16155`](https://youtrack.jetbrains.com/issue/KT-16155) Introduced createCoroutineUnchecked intrinsic
|
||||
|
||||
|
||||
### Gradle support
|
||||
- [`KT-15829`](https://youtrack.jetbrains.com/issue/KT-15829) Gradle Kotlin JS plugin: removed false "Duplicate source root:" warning for kotlin files
|
||||
- [`KT-15902`](https://youtrack.jetbrains.com/issue/KT-15902) JS: gradle task output is now considered as source set output
|
||||
- [`KT-16174`](https://youtrack.jetbrains.com/issue/KT-16174) Error fixed during IDEA-Gradle synchronization for Kotlin JS
|
||||
- [`KT-16267`](https://youtrack.jetbrains.com/issue/KT-16267) JS: fixed regression in 1.1-beta2 for multi-module gradle project
|
||||
- [`KT-16274`](https://youtrack.jetbrains.com/issue/KT-16274) Kotlin JS Gradle unexpected compiler error / absolute path to output file
|
||||
- [`KT-16322`](https://youtrack.jetbrains.com/issue/KT-16322) Circlet project Gradle import issue fixed
|
||||
|
||||
### REPL
|
||||
- [`KT-15861`](https://youtrack.jetbrains.com/issue/KT-15861) Use windows line separator in kotlin's JSR implementation
|
||||
- [`KT-16126`](https://youtrack.jetbrains.com/issue/KT-16126) Proper `jvmTarget` for REPL compilation
|
||||
|
||||
|
||||
## 1.1-Beta2
|
||||
|
||||
### Language related changes
|
||||
|
||||
@@ -29,8 +29,8 @@ internal object KotlinAntTaskUtil {
|
||||
|
||||
private val libPath: File by lazy {
|
||||
// Find path of kotlin-ant.jar in the filesystem and find kotlin-compiler.jar in the same directory
|
||||
val resourcePath = "/" + javaClass.name.replace('.', '/') + ".class"
|
||||
val jarConnection = javaClass.getResource(resourcePath).openConnection() as? JarURLConnection
|
||||
val resourcePath = "/" + this::class.java.name.replace('.', '/') + ".class"
|
||||
val jarConnection = this::class.java.getResource(resourcePath).openConnection() as? JarURLConnection
|
||||
?: throw UnsupportedOperationException("Kotlin compiler Ant task should be loaded from the JAR file")
|
||||
val antTaskJarPath = File(jarConnection.jarFileURL.toURI())
|
||||
|
||||
@@ -54,7 +54,7 @@ internal object KotlinAntTaskUtil {
|
||||
val cached = classLoaderRef.get()
|
||||
if (cached != null) return cached
|
||||
|
||||
val myLoader = javaClass.classLoader
|
||||
val myLoader = this::class.java.classLoader
|
||||
if (myLoader !is AntClassLoader) return myLoader
|
||||
|
||||
val classLoader = ClassPreloadingUtils.preloadClasses(listOf(compilerJar), Preloader.DEFAULT_CLASS_NUMBER_ESTIMATE, myLoader, null)
|
||||
|
||||
@@ -21,10 +21,7 @@ import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.config.KotlinCompilerVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion
|
||||
import org.jetbrains.kotlin.load.kotlin.DeserializedDescriptorResolver
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.build.deserializeFromPlainText
|
||||
import org.jetbrains.kotlin.build.serializeToPlainText
|
||||
|
||||
/**
|
||||
* If you want to add a new field, check its type is supported by [serializeToPlainText], [deserializeFromPlainText]
|
||||
@@ -62,7 +59,7 @@ data class JvmBuildMetaInfo(
|
||||
}
|
||||
|
||||
fun JvmBuildMetaInfo(args: CommonCompilerArguments): JvmBuildMetaInfo =
|
||||
JvmBuildMetaInfo(isEAP = DeserializedDescriptorResolver.IS_PRE_RELEASE,
|
||||
JvmBuildMetaInfo(isEAP = KotlinCompilerVersion.isPreRelease(),
|
||||
compilerBuildVersion = KotlinCompilerVersion.VERSION,
|
||||
languageVersionString = args.languageVersion ?: LanguageVersion.LATEST.versionString,
|
||||
apiVersionString = args.apiVersion ?: ApiVersion.LATEST.versionString,
|
||||
@@ -75,4 +72,4 @@ fun JvmBuildMetaInfo(args: CommonCompilerArguments): JvmBuildMetaInfo =
|
||||
metadataVersionPatch = JvmMetadataVersion.INSTANCE.patch,
|
||||
bytecodeVersionMajor = JvmBytecodeBinaryVersion.INSTANCE.major,
|
||||
bytecodeVersionMinor = JvmBytecodeBinaryVersion.INSTANCE.minor,
|
||||
bytecodeVersionPatch = JvmBytecodeBinaryVersion.INSTANCE.patch)
|
||||
bytecodeVersionPatch = JvmBytecodeBinaryVersion.INSTANCE.patch)
|
||||
|
||||
@@ -19,9 +19,9 @@ package org.jetbrains.kotlin.compilerRunner;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ComparatorUtil;
|
||||
import com.sampullara.cli.Argument;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments;
|
||||
import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -43,7 +43,6 @@ import org.jetbrains.kotlin.serialization.deserialization.TypeTable
|
||||
import org.jetbrains.kotlin.serialization.deserialization.supertypes
|
||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import java.io.File
|
||||
import java.security.MessageDigest
|
||||
@@ -272,7 +271,7 @@ open class IncrementalCacheImpl<Target>(
|
||||
ProtoBuf.Class::getPropertyList
|
||||
) + classData.classProto.enumEntryList.map { classData.nameResolver.getString(it.name) }
|
||||
|
||||
val companionObjectChanged = createChangeInfo(classFqName.parent(), classFqName.shortName().asString().singletonOrEmptyList())
|
||||
val companionObjectChanged = createChangeInfo(classFqName.parent(), listOfNotNull(classFqName.shortName().asString()))
|
||||
val companionObjectMembersChanged = createChangeInfo(classFqName, memberNames)
|
||||
|
||||
listOf(companionObjectMembersChanged, companionObjectChanged)
|
||||
@@ -780,7 +779,7 @@ sealed class ChangeInfo(val fqName: FqName) {
|
||||
protected open fun toStringProperties(): String = "fqName = $fqName"
|
||||
|
||||
override fun toString(): String {
|
||||
return this.javaClass.simpleName + "(${toStringProperties()})"
|
||||
return this::class.java.simpleName + "(${toStringProperties()})"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,5 +50,5 @@ class LocalFileKotlinClass private constructor(
|
||||
|
||||
override fun hashCode(): Int = file.hashCode()
|
||||
override fun equals(other: Any?): Boolean = other is LocalFileKotlinClass && file == other.file
|
||||
override fun toString(): String = "$javaClass: $file"
|
||||
override fun toString(): String = "${this::class.java}: $file"
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ import java.util.*
|
||||
|
||||
|
||||
fun Iterable<File>.javaSourceRoots(roots: Iterable<File>): Iterable<File> =
|
||||
filter { it.isJavaFile() }
|
||||
filter(File::isJavaFile)
|
||||
.map { findSrcDirRoot(it, roots) }
|
||||
.filterNotNull()
|
||||
|
||||
@@ -145,7 +145,7 @@ fun LookupStorage.update(
|
||||
filesToCompile: Iterable<File>,
|
||||
removedFiles: Iterable<File>
|
||||
) {
|
||||
if (lookupTracker !is LookupTrackerImpl) throw AssertionError("Lookup tracker is expected to be LookupTrackerImpl, got ${lookupTracker.javaClass}")
|
||||
if (lookupTracker !is LookupTrackerImpl) throw AssertionError("Lookup tracker is expected to be LookupTrackerImpl, got ${lookupTracker::class.java}")
|
||||
|
||||
removeLookupsFrom(filesToCompile.asSequence() + removedFiles.asSequence())
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ abstract class BasicMap<K : Comparable<K>, V>(
|
||||
fun dump(): String {
|
||||
return with(StringBuilder()) {
|
||||
with(Printer(this)) {
|
||||
println(this@BasicMap.javaClass.simpleName)
|
||||
println(this@BasicMap::class.java.simpleName)
|
||||
pushIndent()
|
||||
|
||||
for (key in storage.keys.sorted()) {
|
||||
|
||||
@@ -131,7 +131,7 @@ object ConstantsMapExternalizer : DataExternalizer<Map<String, Any>> {
|
||||
output.writeByte(Kind.STRING.ordinal)
|
||||
IOUtil.writeString(value, output)
|
||||
}
|
||||
else -> throw IllegalStateException("Unexpected constant class: ${value.javaClass}")
|
||||
else -> throw IllegalStateException("Unexpected constant class: ${value::class.java}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ private fun classFileToString(classFile: File): String {
|
||||
|
||||
out.write("\n------ string table types proto -----\n${DebugJvmProtoBuf.StringTableTypes.parseDelimitedFrom(input)}")
|
||||
|
||||
if (!classHeader!!.metadataVersion.isCompatible()) {
|
||||
if (!classHeader.metadataVersion.isCompatible()) {
|
||||
error("Incompatible class ($classHeader): $classFile")
|
||||
}
|
||||
|
||||
|
||||
@@ -81,8 +81,8 @@ fun getModificationsToPerform(
|
||||
|
||||
val rules = mapOf<String, (String, File) -> Modification>(
|
||||
newSuffix to { path, file -> ModifyContent(path, file) },
|
||||
touchSuffix to { path, file -> TouchFile(path, touchPolicy) },
|
||||
deleteSuffix to { path, file -> DeleteFile(path) }
|
||||
touchSuffix to { path, _ -> TouchFile(path, touchPolicy) },
|
||||
deleteSuffix to { path, _ -> DeleteFile(path) }
|
||||
)
|
||||
|
||||
val modifications = ArrayList<Modification>()
|
||||
@@ -130,7 +130,7 @@ fun getModificationsToPerform(
|
||||
abstract class Modification(val path: String) {
|
||||
abstract fun perform(workDir: File, mapping: MutableMap<File, File>)
|
||||
|
||||
override fun toString(): String = "${javaClass.simpleName} $path"
|
||||
override fun toString(): String = "${this::class.java.simpleName} $path"
|
||||
}
|
||||
|
||||
class ModifyContent(path: String, val dataFile: File) : Modification(path) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
114
build.xml
114
build.xml
@@ -1,4 +1,4 @@
|
||||
<project name="Kotlin" default="dist" xmlns:if="ant:if" xmlns:unless="ant:unless">
|
||||
<project xmlns:if="ant:if" xmlns:unless="ant:unless" name="Kotlin" default="dist">
|
||||
<import file="common.xml" optional="false"/>
|
||||
<property file="resources/kotlinManifest.properties"/>
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
<property name="protobuf-lite.jar" value="${basedir}/dependencies/protobuf-2.6.1-lite.jar"/>
|
||||
<property name="javax.inject.jar" value="${basedir}/lib/javax.inject.jar"/>
|
||||
|
||||
<property name="java.target" value="1.6"/>
|
||||
<property name="java.target" value="1.8"/>
|
||||
<property name="java.target.1.6" value="1.6"/>
|
||||
|
||||
<condition property="bootstrap.or.local.build" value="true">
|
||||
<or>
|
||||
@@ -72,7 +73,6 @@
|
||||
<fileset dir="${basedir}/lib" includes="**/*.jar"/>
|
||||
<fileset dir="${dependencies}" includes="jansi.jar"/>
|
||||
<fileset dir="${dependencies}" includes="jline.jar"/>
|
||||
<fileset dir="${dependencies}" includes="cli-parser-1.1.2.jar"/>
|
||||
<fileset dir="${basedir}/ideaSDK/jps" includes="jps-model.jar"/>
|
||||
</path>
|
||||
|
||||
@@ -406,9 +406,12 @@
|
||||
byline="true" encoding="UTF-8" />
|
||||
</target>
|
||||
|
||||
<target name="js-stdlib">
|
||||
<property environment="env"/>
|
||||
<target name="js-stdlib-preprocess">
|
||||
<kotlin-pp src="libraries/stdlib/src" output="${intermediate-sources}/stdlib/js" profile="JS" />
|
||||
</target>
|
||||
|
||||
<target name="js-stdlib" depends="js-stdlib-preprocess">
|
||||
<property environment="env"/>
|
||||
<cleandir dir="${js.stdlib.output.dir}"/>
|
||||
|
||||
<!-- We don't want descriptors for built-ins to be serialized, so we compile these files separately. -->
|
||||
@@ -474,7 +477,7 @@
|
||||
<copy file="${kotlin-home}/lib/kotlin-stdlib-js.jar" tofile="${kotlin-home}/lib/kotlin-jslib.jar" />
|
||||
</target>
|
||||
|
||||
<target name="pack-js-stdlib-sources">
|
||||
<target name="pack-js-stdlib-sources" depends="js-stdlib-preprocess">
|
||||
<jar destfile="${kotlin-home}/lib/kotlin-stdlib-js-sources.jar" duplicate="fail">
|
||||
<resources refid="js.lib.files" />
|
||||
<fileset refid="kotlin.builtin.files" />
|
||||
@@ -586,7 +589,6 @@
|
||||
<zipfileset src="${idea.sdk}/lib/oromatcher.jar"/>
|
||||
<zipfileset src="${idea.sdk}/jps/jps-model.jar"/>
|
||||
<zipfileset src="${dependencies}/jline.jar"/>
|
||||
<zipfileset src="${dependencies}/cli-parser-1.1.2.jar"/>
|
||||
<zipfileset src="${protobuf.jar}"/>
|
||||
|
||||
<manifest>
|
||||
@@ -617,13 +619,6 @@
|
||||
</target>
|
||||
|
||||
<target name="compiler">
|
||||
<taskdef resource="proguard/ant/task.properties">
|
||||
<classpath>
|
||||
<pathelement path="${dependencies}/proguard.jar"/>
|
||||
<pathelement path="${dependencies}/proguard-anttask.jar"/>
|
||||
</classpath>
|
||||
</taskdef>
|
||||
|
||||
<cleandir dir="${output}/classes/compiler"/>
|
||||
|
||||
<javac2 destdir="${output}/classes/compiler" debug="true" debuglevel="lines,vars,source" includeAntRuntime="false"
|
||||
@@ -645,17 +640,32 @@
|
||||
unless:true="${shrink}" />
|
||||
|
||||
<sequential if:true="${shrink}">
|
||||
<shrink configuration="${basedir}/compiler/compiler.pro"/>
|
||||
</sequential>
|
||||
|
||||
<pack-compiler-for-maven/>
|
||||
</target>
|
||||
|
||||
<macrodef name="shrink">
|
||||
<attribute name="configuration"/>
|
||||
|
||||
<sequential>
|
||||
<taskdef resource="proguard/ant/task.properties">
|
||||
<classpath>
|
||||
<pathelement path="${dependencies}/proguard.jar"/>
|
||||
<pathelement path="${dependencies}/proguard-anttask.jar"/>
|
||||
</classpath>
|
||||
</taskdef>
|
||||
|
||||
<available property="rtjar" value="${java.home}/lib/rt.jar" file="${java.home}/lib/rt.jar"/>
|
||||
<available property="rtjar" value="${java.home}/../Classes/classes.jar" file="${java.home}/../Classes/classes.jar"/>
|
||||
|
||||
<available property="jssejar" value="${java.home}/lib/jsse.jar" file="${java.home}/lib/jsse.jar"/>
|
||||
<available property="jssejar" value="${java.home}/../Classes/jsse.jar" file="${java.home}/../Classes/jsse.jar"/>
|
||||
|
||||
<proguard configuration="${basedir}/compiler/compiler.pro"/>
|
||||
<proguard configuration="@{configuration}"/>
|
||||
</sequential>
|
||||
|
||||
<pack-compiler-for-maven/>
|
||||
</target>
|
||||
</macrodef>
|
||||
|
||||
<macrodef name="pack-compiler-for-maven">
|
||||
<sequential>
|
||||
@@ -756,7 +766,7 @@
|
||||
<attribute name="Built-By" value="${manifest.impl.vendor}"/>
|
||||
|
||||
<attribute name="Implementation-Vendor" value="${manifest.impl.vendor}"/>
|
||||
<attribute name="Implementation-Title" value="${manifest.impl.title.kotlin.daemon-client}"/>
|
||||
<attribute name="Implementation-Title" value="${manifest.impl.title.kotlin.daemon.client}"/>
|
||||
<attribute name="Implementation-Version" value="${build.number}"/>
|
||||
</manifest>
|
||||
</jar>
|
||||
@@ -776,6 +786,27 @@
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="compiler-client-embeddable">
|
||||
<taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask" classpath="dependencies/jarjar.jar"/>
|
||||
|
||||
<jarjar jarfile="${output}/kotlin-compiler-client-embeddable-before-shrink.jar">
|
||||
<zipfileset file="${kotlin-home}/build.txt" prefix="META-INF"/>
|
||||
<zipfileset src="${kotlin-home}/lib/kotlin-daemon-client.jar"/>
|
||||
<fileset dir="${output}/classes/compiler"
|
||||
includes="org/jetbrains/kotlin/daemon/common/** org/jetbrains/kotlin/cli/common/messages/CompilerMessage* org/jetbrains/kotlin/cli/common/messages/Message* org/jetbrains/kotlin/cli/common/repl/**"/>
|
||||
|
||||
<manifest>
|
||||
<attribute name="Built-By" value="${manifest.impl.vendor}"/>
|
||||
<attribute name="Implementation-Vendor" value="${manifest.impl.vendor}"/>
|
||||
<attribute name="Implementation-Title" value="${manifest.impl.title.kotlin.compiler.client,embeddable}"/>
|
||||
<attribute name="Implementation-Version" value="${build.number}"/>
|
||||
<attribute name="Class-Path" value="kotlin-stdlib.jar"/>
|
||||
</manifest>
|
||||
</jarjar>
|
||||
|
||||
<shrink configuration="${basedir}/compiler/compiler-client.pro"/>
|
||||
</target>
|
||||
|
||||
<target name="android-extensions-compiler">
|
||||
<cleandir dir="${output}/classes/android-extensions/android-extensions-compiler"/>
|
||||
<javac2 destdir="${output}/classes/android-extensions/android-extensions-compiler" debug="true" debuglevel="lines,vars,source" includeAntRuntime="false">
|
||||
@@ -868,6 +899,29 @@
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="source-sections-compiler-plugin">
|
||||
<cleandir dir="${output}/classes/source-sections-compiler-plugin"/>
|
||||
<javac2 destdir="${output}/classes/source-sections-compiler-plugin" debug="true" debuglevel="lines,vars,source" includeAntRuntime="false">
|
||||
<withKotlin modulename="source-sections">
|
||||
<compilerarg value="-version"/>
|
||||
</withKotlin>
|
||||
<skip pattern="kotlin/Metadata"/>
|
||||
<src>
|
||||
<pathelement path="plugins/source-sections/source-sections-compiler/src"/>
|
||||
</src>
|
||||
<classpath>
|
||||
<pathelement path="${idea.sdk}/core/intellij-core.jar"/>
|
||||
<pathelement path="${kotlin-home}/lib/kotlin-compiler.jar"/>
|
||||
</classpath>
|
||||
</javac2>
|
||||
|
||||
<jar destfile="${kotlin-home}/lib/source-sections-compiler-plugin.jar">
|
||||
<fileset dir="${output}/classes/source-sections-compiler-plugin"/>
|
||||
<zipfileset file="${kotlin-home}/build.txt" prefix="META-INF"/>
|
||||
<fileset dir="${basedir}/plugins/source-sections/source-sections-compiler/src" includes="META-INF/services/**"/>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="annotation-processing-under-jdk8">
|
||||
<property environment="env"/>
|
||||
|
||||
@@ -1005,7 +1059,7 @@
|
||||
</java>
|
||||
|
||||
<javac2 srcdir="${toString:src.dirset}" destdir="@{output}" debug="true" debuglevel="lines,vars,source"
|
||||
includeAntRuntime="false" source="${java.target}" target="${java.target}">
|
||||
includeAntRuntime="false" source="${java.target.1.6}" target="${java.target.1.6}">
|
||||
<skip pattern="kotlin/Metadata"/>
|
||||
<classpath>
|
||||
<path refid="classpath.path"/>
|
||||
@@ -1024,13 +1078,13 @@
|
||||
<sequential>
|
||||
<java classname="org.jetbrains.kotlin.preloading.Preloader" failonerror="true" fork="true" maxmemory="${max.heap.size.for.forked.jvm}">
|
||||
<classpath>
|
||||
<pathelement location="${kotlin-home}/lib/kotlin-preloader.jar"/>
|
||||
<pathelement location="${bootstrap.compiler.home}/lib/kotlin-preloader.jar"/>
|
||||
</classpath>
|
||||
<assertions>
|
||||
<enable/>
|
||||
</assertions>
|
||||
<arg value="-cp"/>
|
||||
<arg value="${kotlin-home}/lib/kotlin-compiler.jar"/>
|
||||
<arg value="${bootstrap.compiler.home}/lib/kotlin-compiler.jar"/>
|
||||
<arg value="org.jetbrains.kotlin.preprocessor.PreprocessorCLI"/>
|
||||
<arg value="@{src}"/>
|
||||
<arg value="@{output}"/>
|
||||
@@ -1224,11 +1278,10 @@
|
||||
</manifest>
|
||||
</jar>
|
||||
|
||||
<delete file="${output}/kotlin-reflect-jarjar.jar" failonerror="false"/>
|
||||
|
||||
<sequential if:true="${obfuscate.reflect}">
|
||||
<taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask" classpath="dependencies/jarjar.jar"/>
|
||||
<jarjar jarfile="${output}/kotlin-reflect-jarjar.jar" filesonly="true" filesetmanifest="merge">
|
||||
<delete file="${output}/kotlin-reflect-after-jarjar.jar" failonerror="false"/>
|
||||
<jarjar jarfile="${output}/kotlin-reflect-after-jarjar.jar" filesonly="true" filesetmanifest="merge">
|
||||
<zipfileset src="${output}/kotlin-reflect-before-jarjar.jar"/>
|
||||
<rule pattern="org.jetbrains.kotlin.**" result="kotlin.reflect.jvm.internal.impl.@1"/>
|
||||
<rule pattern="javax.inject.**" result="kotlin.reflect.jvm.internal.impl.javax.inject.@1"/>
|
||||
@@ -1239,17 +1292,18 @@
|
||||
<compilerarg value="-script"/>
|
||||
<compilerarg value="kotlin/Metadata"/> <!-- Annotation to strip -->
|
||||
<compilerarg value="kotlin/reflect/jvm/internal/impl/.*"/> <!-- Classes to strip from -->
|
||||
<compilerarg value="${output}/kotlin-reflect-jarjar.jar"/>
|
||||
<compilerarg value="${kotlin-home}/lib/kotlin-reflect.jar"/>
|
||||
<compilerarg value="${output}/kotlin-reflect-after-jarjar.jar"/>
|
||||
<compilerarg value="${output}/kotlin-reflect-before-proguard.jar"/>
|
||||
<classpath>
|
||||
<pathelement location="${idea.sdk}/lib/asm-all.jar"/>
|
||||
</classpath>
|
||||
</kotlinc>
|
||||
|
||||
<shrink configuration="${basedir}/core/reflection.jvm/reflection.pro"/>
|
||||
</sequential>
|
||||
|
||||
<sequential unless:true="${obfuscate.reflect}">
|
||||
<echo message="Obfuscation of kotlin-reflect is disabled"/>
|
||||
<copy file="${output}/kotlin-reflect-before-jarjar.jar" tofile="${output}/kotlin-reflect-jarjar.jar" overwrite="true"/>
|
||||
<copy file="${output}/kotlin-reflect-before-jarjar.jar" tofile="${kotlin-home}/lib/kotlin-reflect.jar" overwrite="true"/>
|
||||
</sequential>
|
||||
</target>
|
||||
@@ -1330,11 +1384,11 @@
|
||||
depends="builtins,stdlib,kotlin-test,core,reflection,pack-runtime,pack-runtime-sources,script-runtime,mock-runtime-for-test"/>
|
||||
|
||||
<target name="dist"
|
||||
depends="clean,init,prepare-dist,preloader,runner,serialize-builtins,compiler,compiler-sources,ant-tools,runtime,kotlin-js-stdlib,android-extensions-compiler,allopen-compiler-plugin,noarg-compiler-plugin,sam-with-receiver-compiler-plugin,annotation-processing-under-jdk8,daemon-client,kotlin-build-common-test"
|
||||
depends="clean,init,prepare-dist,preloader,runner,serialize-builtins,compiler,compiler-sources,ant-tools,runtime,kotlin-js-stdlib,android-extensions-compiler,allopen-compiler-plugin,noarg-compiler-plugin,sam-with-receiver-compiler-plugin,source-sections-compiler-plugin,annotation-processing-under-jdk8,daemon-client,kotlin-build-common-test"
|
||||
description="Builds redistributables from sources"/>
|
||||
|
||||
<target name="dist-quick"
|
||||
depends="clean,init,prepare-dist,preloader,serialize-builtins,compiler-quick,ant-tools,runtime,kotlin-js-stdlib,android-extensions-compiler,allopen-compiler-plugin,noarg-compiler-plugin,sam-with-receiver-compiler-plugin,annotation-processing-under-jdk8"
|
||||
depends="clean,init,prepare-dist,preloader,serialize-builtins,compiler-quick,ant-tools,runtime,kotlin-js-stdlib,android-extensions-compiler,allopen-compiler-plugin,noarg-compiler-plugin,sam-with-receiver-compiler-plugin,source-sections-compiler-plugin,annotation-processing-under-jdk8"
|
||||
description="Builds everything, but classes are reused from project out dir, doesn't run proguard and javadoc"/>
|
||||
|
||||
<target name="dist-quick-compiler-only"
|
||||
|
||||
@@ -29,8 +29,8 @@ public class AndroidJpsBuildTestCase extends BaseKotlinJpsBuildTestCase {
|
||||
|
||||
public void doTest() {
|
||||
initProject();
|
||||
rebuildAll();
|
||||
makeAll().assertSuccessful();
|
||||
rebuildAllModules();
|
||||
buildAllModules().assertSuccessful();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -91,7 +91,7 @@ object CodegenUtil {
|
||||
else if (traitMember is PropertyDescriptor) {
|
||||
for (traitAccessor in traitMember.accessors) {
|
||||
for (inheritedAccessor in (copy as PropertyDescriptor).accessors) {
|
||||
if (inheritedAccessor.javaClass == traitAccessor.javaClass) { // same accessor kind
|
||||
if (inheritedAccessor::class.java == traitAccessor::class.java) { // same accessor kind
|
||||
result.put(traitAccessor, inheritedAccessor)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,5 +103,5 @@ abstract class DataClassMethodGenerator(private val declaration: KtClassOrObject
|
||||
.map { bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, it)!! }
|
||||
|
||||
private val primaryConstructorParameters: List<KtParameter>
|
||||
get() = (declaration as? KtClass)?.getPrimaryConstructorParameters().orEmpty()
|
||||
get() = (declaration as? KtClass)?.primaryConstructorParameters.orEmpty()
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
|
||||
@@ -31,7 +32,12 @@ abstract class ArgumentGenerator {
|
||||
*
|
||||
* @see kotlin.reflect.jvm.internal.KCallableImpl.callBy
|
||||
*/
|
||||
open fun generate(valueArgumentsByIndex: List<ResolvedValueArgument>, actualArgs: List<ResolvedValueArgument>): DefaultCallArgs {
|
||||
open fun generate(
|
||||
valueArgumentsByIndex: List<ResolvedValueArgument>,
|
||||
actualArgs: List<ResolvedValueArgument>,
|
||||
// may be null for a constructor of an object literal
|
||||
calleeDescriptor: CallableDescriptor?
|
||||
): DefaultCallArgs {
|
||||
assert(valueArgumentsByIndex.size == actualArgs.size) {
|
||||
"Value arguments collection should have same size, but ${valueArgumentsByIndex.size} != ${actualArgs.size}"
|
||||
}
|
||||
@@ -48,7 +54,8 @@ abstract class ArgumentGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
val defaultArgs = DefaultCallArgs(valueArgumentsByIndex.size)
|
||||
// Use unwrapped version, because additional synthetic parameters can't have default values
|
||||
val defaultArgs = DefaultCallArgs(calleeDescriptor?.unwrapFrontendVersion()?.valueParameters?.size ?: 0)
|
||||
|
||||
for (argumentWithDeclIndex in actualArgsWithDeclIndex) {
|
||||
val argument = argumentWithDeclIndex.arg
|
||||
|
||||
@@ -770,6 +770,7 @@ public class AsmUtil {
|
||||
if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
|
||||
if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
|
||||
if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
|
||||
if (left == Type.CHAR_TYPE || right == Type.CHAR_TYPE) return Type.CHAR_TYPE;
|
||||
return Type.INT_TYPE;
|
||||
}
|
||||
|
||||
|
||||
@@ -210,7 +210,12 @@ class NumberCompare(
|
||||
) : BranchedValue(left, right, operandType, NumberCompare.getNumberCompareOpcode(opToken)) {
|
||||
|
||||
override fun patchOpcode(opcode: Int, v: InstructionAdapter): Int {
|
||||
when (operandType) {
|
||||
// Opcode takes one int operand from the stack
|
||||
assert(opcode in IFEQ..IFLE) {
|
||||
"Opcode for comparing must be in range ${IFEQ..IFLE}, but $opcode was found"
|
||||
}
|
||||
|
||||
return when (operandType) {
|
||||
Type.FLOAT_TYPE, Type.DOUBLE_TYPE -> {
|
||||
if (opToken == KtTokens.GT || opToken == KtTokens.GTEQ) {
|
||||
v.cmpl(operandType)
|
||||
@@ -218,17 +223,19 @@ class NumberCompare(
|
||||
else {
|
||||
v.cmpg(operandType)
|
||||
}
|
||||
|
||||
opcode
|
||||
}
|
||||
Type.LONG_TYPE -> {
|
||||
v.lcmp()
|
||||
|
||||
opcode
|
||||
}
|
||||
else -> {
|
||||
return opcode + (IF_ICMPEQ - IFEQ)
|
||||
opcode + (IF_ICMPEQ - IFEQ)
|
||||
}
|
||||
}
|
||||
return opcode
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getNumberCompareOpcode(opToken: IElementType): Int {
|
||||
return when (opToken) {
|
||||
@@ -262,4 +269,4 @@ class ObjectCompare(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,13 @@
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
import org.jetbrains.kotlin.psi.ValueArgument;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*;
|
||||
import org.jetbrains.kotlin.types.FlexibleTypesKt;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
import java.util.List;
|
||||
@@ -53,11 +56,12 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator {
|
||||
@Override
|
||||
public DefaultCallArgs generate(
|
||||
@NotNull List<? extends ResolvedValueArgument> valueArgumentsByIndex,
|
||||
@NotNull List<? extends ResolvedValueArgument> valueArgs
|
||||
@NotNull List<? extends ResolvedValueArgument> valueArgs,
|
||||
@Nullable CallableDescriptor calleeDescriptor
|
||||
) {
|
||||
boolean shouldMarkLineNumbers = this.codegen.isShouldMarkLineNumbers();
|
||||
this.codegen.setShouldMarkLineNumbers(false);
|
||||
DefaultCallArgs defaultArgs = super.generate(valueArgumentsByIndex, valueArgs);
|
||||
DefaultCallArgs defaultArgs = super.generate(valueArgumentsByIndex, valueArgs, calleeDescriptor);
|
||||
this.codegen.setShouldMarkLineNumbers(shouldMarkLineNumbers);
|
||||
return defaultArgs;
|
||||
}
|
||||
@@ -84,7 +88,9 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator {
|
||||
protected void generateVararg(int i, @NotNull VarargValueArgument argument) {
|
||||
ValueParameterDescriptor parameter = valueParameters.get(i);
|
||||
Type type = valueParameterTypes.get(i);
|
||||
codegen.genVarargs(argument, parameter.getType());
|
||||
// Upper bound for type of vararg parameter should always have a form of 'Array<out T>',
|
||||
// while its lower bound may be Nothing-typed after approximation
|
||||
codegen.genVarargs(argument, FlexibleTypesKt.upperIfFlexible(parameter.getType()));
|
||||
callGenerator.afterParameterPut(type, null, i);
|
||||
}
|
||||
|
||||
|
||||
@@ -77,9 +77,13 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
|
||||
}
|
||||
}
|
||||
|
||||
generatePrimaryConstructorProperties();
|
||||
generateConstructors();
|
||||
generateDefaultImplsIfNeeded();
|
||||
boolean generateNonClassMembers = shouldGenerateNonClassMembers();
|
||||
|
||||
if (generateNonClassMembers) {
|
||||
generatePrimaryConstructorProperties();
|
||||
generateConstructors();
|
||||
generateDefaultImplsIfNeeded();
|
||||
}
|
||||
|
||||
// Generate _declared_ companions
|
||||
for (KtObjectDeclaration companion : companions) {
|
||||
@@ -92,23 +96,30 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
|
||||
genSyntheticClassOrObject((SyntheticClassOrObjectDescriptor) companionObjectDescriptor);
|
||||
}
|
||||
|
||||
if (!DescriptorUtils.isInterface(descriptor)) {
|
||||
for (DeclarationDescriptor memberDescriptor : DescriptorUtils.getAllDescriptors(descriptor.getDefaultType().getMemberScope())) {
|
||||
if (memberDescriptor instanceof CallableMemberDescriptor) {
|
||||
CallableMemberDescriptor member = (CallableMemberDescriptor) memberDescriptor;
|
||||
if (!member.getKind().isReal() && ImplKt.findInterfaceImplementation(member) == null) {
|
||||
if (member instanceof FunctionDescriptor) {
|
||||
functionCodegen.generateBridges((FunctionDescriptor) member);
|
||||
if (generateNonClassMembers) {
|
||||
generateBridges();
|
||||
}
|
||||
}
|
||||
|
||||
private void generateBridges() {
|
||||
if (DescriptorUtils.isInterface(descriptor)) {
|
||||
return;
|
||||
}
|
||||
for (DeclarationDescriptor memberDescriptor : DescriptorUtils.getAllDescriptors(descriptor.getDefaultType().getMemberScope())) {
|
||||
if (memberDescriptor instanceof CallableMemberDescriptor) {
|
||||
CallableMemberDescriptor member = (CallableMemberDescriptor) memberDescriptor;
|
||||
if (!member.getKind().isReal() && ImplKt.findInterfaceImplementation(member) == null) {
|
||||
if (member instanceof FunctionDescriptor) {
|
||||
functionCodegen.generateBridges((FunctionDescriptor) member);
|
||||
}
|
||||
else if (member instanceof PropertyDescriptor) {
|
||||
PropertyGetterDescriptor getter = ((PropertyDescriptor) member).getGetter();
|
||||
if (getter != null) {
|
||||
functionCodegen.generateBridges(getter);
|
||||
}
|
||||
else if (member instanceof PropertyDescriptor) {
|
||||
PropertyGetterDescriptor getter = ((PropertyDescriptor) member).getGetter();
|
||||
if (getter != null) {
|
||||
functionCodegen.generateBridges(getter);
|
||||
}
|
||||
PropertySetterDescriptor setter = ((PropertyDescriptor) member).getSetter();
|
||||
if (setter != null) {
|
||||
functionCodegen.generateBridges(setter);
|
||||
}
|
||||
PropertySetterDescriptor setter = ((PropertyDescriptor) member).getSetter();
|
||||
if (setter != null) {
|
||||
functionCodegen.generateBridges(setter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,6 +127,11 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldGenerateNonClassMembers() {
|
||||
return !(myClass instanceof KtClassOrObject) ||
|
||||
state.getGenerateDeclaredClassFilter().shouldGenerateClassMembers((KtClassOrObject) myClass);
|
||||
}
|
||||
|
||||
protected void generateConstructors() {
|
||||
|
||||
}
|
||||
@@ -130,7 +146,9 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
|
||||
|
||||
protected void generateDeclaration(KtDeclaration declaration) {
|
||||
if (declaration instanceof KtProperty || declaration instanceof KtNamedFunction || declaration instanceof KtTypeAlias) {
|
||||
genSimpleMember(declaration);
|
||||
if (shouldGenerateNonClassMembers()) {
|
||||
genSimpleMember(declaration);
|
||||
}
|
||||
}
|
||||
else if (declaration instanceof KtClassOrObject) {
|
||||
if (declaration instanceof KtEnumEntry && !enumEntryNeedSubclass(bindingContext, (KtEnumEntry) declaration)) {
|
||||
|
||||
@@ -55,20 +55,12 @@ public class ClassBuilderFactories {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
};
|
||||
|
||||
public static ClassBuilderFactory TEST_KAPT3 = new TestClassBuilderFactory(false) {
|
||||
@NotNull
|
||||
@Override
|
||||
public ClassBuilderMode getClassBuilderMode() {
|
||||
return ClassBuilderMode.KAPT3;
|
||||
}
|
||||
};
|
||||
|
||||
public static ClassBuilderFactory TEST = new TestClassBuilderFactory(false);
|
||||
|
||||
public static ClassBuilderFactory TEST_WITH_SOURCE_RETENTION_ANNOTATIONS = new TestClassBuilderFactory(true);
|
||||
|
||||
private static class TestClassBuilderFactory implements ClassBuilderFactory {
|
||||
public static class TestClassBuilderFactory implements ClassBuilderFactory {
|
||||
private final boolean generateSourceRetentionAnnotations;
|
||||
|
||||
public TestClassBuilderFactory(boolean generateSourceRetentionAnnotations) {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
public class ClassBuilderMode {
|
||||
public final boolean generateBodies;
|
||||
public final boolean generateMetadata;
|
||||
@@ -73,4 +75,11 @@ public class ClassBuilderMode {
|
||||
/* metadata = */ true,
|
||||
/* sourceRetention = */ true,
|
||||
/* generateMultiFileFacadePartClasses = */ true);
|
||||
|
||||
@TestOnly
|
||||
public final static ClassBuilderMode LIGHT_ANALYSIS_FOR_TESTS = new ClassBuilderMode(
|
||||
/* bodies = */ false,
|
||||
/* metadata = */ true,
|
||||
/* sourceRetention = */ false,
|
||||
/* generateMultiFileFacadePartClasses = */ true);
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ public class ClassFileFactory implements OutputFileCollection {
|
||||
return answer;
|
||||
}
|
||||
|
||||
void done() {
|
||||
public void done() {
|
||||
if (!isDone) {
|
||||
isDone = true;
|
||||
writeModuleMappings();
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmOverloadsAnnotation
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
@@ -55,7 +54,7 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
|
||||
contextKind: OwnerKind,
|
||||
classOrObject: KtPureClassOrObject
|
||||
) {
|
||||
val methodElement = classOrObject.getPrimaryConstructor() ?: classOrObject
|
||||
val methodElement = classOrObject.primaryConstructor ?: classOrObject
|
||||
|
||||
if (generateOverloadsIfNeeded(methodElement, constructorDescriptor, constructorDescriptor, contextKind, classBuilder, memberCodegen)) {
|
||||
return
|
||||
@@ -129,12 +128,14 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
|
||||
) {
|
||||
val typeMapper = state.typeMapper
|
||||
val isStatic = AsmUtil.isStaticMethod(contextKind, functionDescriptor)
|
||||
val flags = AsmUtil.getCommonCallableFlags(functionDescriptor) or
|
||||
(if (isStatic) Opcodes.ACC_STATIC else 0) or
|
||||
(if (functionDescriptor.modality == Modality.FINAL && functionDescriptor !is ConstructorDescriptor) Opcodes.ACC_FINAL else 0)
|
||||
|
||||
val baseMethodFlags = AsmUtil.getCommonCallableFlags(functionDescriptor) and Opcodes.ACC_VARARGS.inv()
|
||||
val remainingParameters = getRemainingParameters(functionDescriptor.original, substituteCount)
|
||||
val signature = typeMapper.mapSignature(functionDescriptor, contextKind, remainingParameters, false)
|
||||
val flags =
|
||||
baseMethodFlags or
|
||||
(if (isStatic) Opcodes.ACC_STATIC else 0) or
|
||||
(if (functionDescriptor.modality == Modality.FINAL && functionDescriptor !is ConstructorDescriptor) Opcodes.ACC_FINAL else 0) or
|
||||
(if (remainingParameters.lastOrNull()?.varargElementType != null) Opcodes.ACC_VARARGS else 0)
|
||||
val signature = typeMapper.mapSignatureWithCustomParameters(functionDescriptor, contextKind, remainingParameters, false)
|
||||
val mv = classBuilder.newMethod(OtherOrigin(methodElement, functionDescriptor), flags,
|
||||
signature.asmMethod.name,
|
||||
signature.asmMethod.descriptor,
|
||||
@@ -250,7 +251,7 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
|
||||
val classDescriptor = constructorDescriptor.constructedClass
|
||||
if (classDescriptor.kind != ClassKind.CLASS) return false
|
||||
|
||||
if (classOrObject.isLocal()) return false
|
||||
if (classOrObject.isLocal) return false
|
||||
|
||||
if (CodegenBinding.canHaveOuter(state.bindingContext, classDescriptor)) return false
|
||||
|
||||
@@ -264,6 +265,6 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
|
||||
}
|
||||
|
||||
private fun hasSecondaryConstructorsWithNoParameters(klass: KtClass) =
|
||||
klass.getSecondaryConstructors().any { it.valueParameters.isEmpty() }
|
||||
klass.secondaryConstructors.any { it.valueParameters.isEmpty() }
|
||||
|
||||
}
|
||||
|
||||
@@ -33,10 +33,10 @@ abstract class DelegatingClassBuilderFactory(
|
||||
abstract override fun newClassBuilder(origin: JvmDeclarationOrigin): DelegatingClassBuilder
|
||||
|
||||
override fun asBytes(builder: ClassBuilder?): ByteArray? {
|
||||
return delegate.asBytes((builder as DelegatingClassBuilder).getDelegate())
|
||||
return delegate.asBytes((builder as DelegatingClassBuilder).delegate)
|
||||
}
|
||||
|
||||
override fun asText(builder: ClassBuilder?): String? {
|
||||
return delegate.asText((builder as DelegatingClassBuilder).getDelegate())
|
||||
return delegate.asText((builder as DelegatingClassBuilder).delegate)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1709,7 +1709,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
ArgumentGenerator argumentGenerator =
|
||||
new CallBasedArgumentGenerator(ExpressionCodegen.this, defaultCallGenerator, valueParameters, mappedTypes);
|
||||
|
||||
argumentGenerator.generate(valueArguments, valueArguments);
|
||||
argumentGenerator.generate(valueArguments, valueArguments, null);
|
||||
}
|
||||
|
||||
Collection<ClassConstructorDescriptor> constructors = classDescriptor.getConstructors();
|
||||
@@ -1919,11 +1919,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
return asmType(varType);
|
||||
}
|
||||
|
||||
private static boolean isSharedVarType(@NotNull Type type) {
|
||||
return type.getSort() == Type.OBJECT && type.getInternalName().startsWith(REF_TYPE_PREFIX);
|
||||
}
|
||||
|
||||
|
||||
private void putDescriptorIntoFrameMap(@NotNull KtElement statement) {
|
||||
if (statement instanceof KtDestructuringDeclaration) {
|
||||
KtDestructuringDeclaration multiDeclaration = (KtDestructuringDeclaration) statement;
|
||||
@@ -2867,7 +2862,11 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
assert valueArguments != null : "Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor();
|
||||
|
||||
DefaultCallArgs defaultArgs =
|
||||
argumentGenerator.generate(valueArguments, new ArrayList<ResolvedValueArgument>(resolvedCall.getValueArguments().values()));
|
||||
argumentGenerator.generate(
|
||||
valueArguments,
|
||||
new ArrayList<ResolvedValueArgument>(resolvedCall.getValueArguments().values()),
|
||||
resolvedCall.getResultingDescriptor()
|
||||
);
|
||||
|
||||
if (tailRecursionCodegen.isTailRecursion(resolvedCall)) {
|
||||
tailRecursionCodegen.generateTailRecursion(resolvedCall);
|
||||
@@ -3192,7 +3191,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
boolean isSingleton = calleeContainingClass.getKind().isSingleton();
|
||||
if (isSingleton) {
|
||||
if (calleeContainingClass.equals(context.getThisDescriptor()) &&
|
||||
!CodegenUtilKt.isJvmStaticInObjectOrClass(context.getContextDescriptor())) {
|
||||
!CodegenUtilKt.isJvmStaticInObjectOrClass(context.getFunctionDescriptor())) {
|
||||
return StackValue.local(0, typeMapper.mapType(calleeContainingClass));
|
||||
}
|
||||
else if (isEnumEntry(calleeContainingClass)) {
|
||||
@@ -4316,6 +4315,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
private static ReceiverValue getConstructorReceiver(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
CallableDescriptor constructor = resolvedCall.getResultingDescriptor();
|
||||
if (constructor.getExtensionReceiverParameter() != null) {
|
||||
// see comment on `withDispatchReceiver` parameter in
|
||||
// org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptorImpl.Companion.createIfAvailable
|
||||
assert constructor instanceof TypeAliasConstructorDescriptor :
|
||||
"Only type alias constructor can have an extension receiver: " + constructor;
|
||||
return resolvedCall.getExtensionReceiver();
|
||||
@@ -4907,7 +4908,8 @@ The "returned" value of try expression with no finally is either the last expres
|
||||
public NameGenerator getInlineNameGenerator() {
|
||||
NameGenerator nameGenerator = getParentCodegen().getInlineNameGenerator();
|
||||
Name name = context.getContextDescriptor().getName();
|
||||
return nameGenerator.subGenerator((name.isSpecial() ? "$special" : name.asString()) + "$$inlined" );
|
||||
String inlinedName = name.isSpecial() ? InlineCodegenUtil.SPECIAL_TRANSFORMATION_NAME : name.asString();
|
||||
return nameGenerator.subGenerator(inlinedName + InlineCodegenUtil.INLINE_CALL_TRANSFORMATION_SUFFIX);
|
||||
}
|
||||
|
||||
public Type getReturnType() {
|
||||
|
||||
@@ -231,7 +231,7 @@ public class FunctionCodegen {
|
||||
boolean staticInCompanionObject = CodegenUtilKt.isJvmStaticInCompanionObject(functionDescriptor);
|
||||
if (staticInCompanionObject) {
|
||||
ImplementationBodyCodegen parentBodyCodegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
|
||||
parentBodyCodegen.addAdditionalTask(new JvmStaticGenerator(functionDescriptor, origin, state, parentBodyCodegen));
|
||||
parentBodyCodegen.addAdditionalTask(new JvmStaticInCompanionObjectGenerator(functionDescriptor, origin, state, parentBodyCodegen));
|
||||
}
|
||||
|
||||
if (!state.getClassBuilderMode().generateBodies || isAbstractMethod(functionDescriptor, contextKind, state)) {
|
||||
@@ -256,7 +256,8 @@ public class FunctionCodegen {
|
||||
else if (staticInCompanionObject) {
|
||||
// native @JvmStatic foo() in companion object should delegate to the static native function moved to the outer class
|
||||
mv.visitCode();
|
||||
FunctionDescriptor staticFunctionDescriptor = JvmStaticGenerator.createStaticFunctionDescriptor(functionDescriptor);
|
||||
FunctionDescriptor staticFunctionDescriptor = JvmStaticInCompanionObjectGenerator
|
||||
.createStaticFunctionDescriptor(functionDescriptor);
|
||||
Method accessorMethod =
|
||||
typeMapper.mapAsmMethod(memberCodegen.getContext().accessibleDescriptor(staticFunctionDescriptor, null));
|
||||
Type owningType = typeMapper.mapClass((ClassifierDescriptor) staticFunctionDescriptor.getContainingDeclaration());
|
||||
@@ -919,17 +920,23 @@ public class FunctionCodegen {
|
||||
// enum constructors have two additional synthetic parameters which somewhat complicate this task
|
||||
AnnotationCodegen.forMethod(mv, memberCodegen, typeMapper).genAnnotations(functionDescriptor, defaultMethod.getReturnType());
|
||||
|
||||
if (state.getClassBuilderMode().generateBodies) {
|
||||
if (this.owner instanceof MultifileClassFacadeContext) {
|
||||
mv.visitCode();
|
||||
generateFacadeDelegateMethodBody(mv, defaultMethod, (MultifileClassFacadeContext) this.owner);
|
||||
if (!state.getClassBuilderMode().generateBodies) {
|
||||
if (this.owner instanceof MultifileClassFacadeContext)
|
||||
endVisit(mv, "default method delegation", getSourceFromDescriptor(functionDescriptor));
|
||||
}
|
||||
else {
|
||||
mv.visitCode();
|
||||
generateDefaultImplBody(owner, functionDescriptor, mv, loadStrategy, function, memberCodegen, defaultMethod);
|
||||
else
|
||||
endVisit(mv, "default method", getSourceFromDescriptor(functionDescriptor));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.owner instanceof MultifileClassFacadeContext) {
|
||||
mv.visitCode();
|
||||
generateFacadeDelegateMethodBody(mv, defaultMethod, (MultifileClassFacadeContext) this.owner);
|
||||
endVisit(mv, "default method delegation", getSourceFromDescriptor(functionDescriptor));
|
||||
}
|
||||
else {
|
||||
mv.visitCode();
|
||||
generateDefaultImplBody(owner, functionDescriptor, mv, loadStrategy, function, memberCodegen, defaultMethod);
|
||||
endVisit(mv, "default method", getSourceFromDescriptor(functionDescriptor));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isObject;
|
||||
|
||||
public class FunctionReferenceGenerationStrategy extends FunctionGenerationStrategy.CodegenBased {
|
||||
private final ResolvedCall<?> resolvedCall;
|
||||
private final FunctionDescriptor referencedFunction;
|
||||
@@ -146,6 +148,12 @@ public class FunctionReferenceGenerationStrategy extends FunctionGenerationStrat
|
||||
(referencedFunction.getExtensionReceiverParameter() != null ? 1 : 0) -
|
||||
(receiverType != null ? 1 : 0);
|
||||
|
||||
if (receivers < 0 && referencedFunction instanceof ConstructorDescriptor && isObject(referencedFunction.getContainingDeclaration().getContainingDeclaration())) {
|
||||
//reference to object nested class
|
||||
//TODO: seems problem should be fixed on frontend side (note that object instance are captured by generated class)
|
||||
receivers = 0;
|
||||
}
|
||||
|
||||
List<ValueParameterDescriptor> parameters = CollectionsKt.drop(functionDescriptor.getValueParameters(), receivers);
|
||||
for (int i = 0; i < parameters.size(); i++) {
|
||||
ValueParameterDescriptor parameter = parameters.get(i);
|
||||
|
||||
@@ -88,6 +88,7 @@ import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.
|
||||
import static org.jetbrains.kotlin.types.Variance.INVARIANT;
|
||||
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isLocalFunction;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
|
||||
import static org.jetbrains.org.objectweb.asm.Type.getObjectType;
|
||||
|
||||
public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
private static final String ENUM_VALUES_FIELD_NAME = "$VALUES";
|
||||
@@ -113,7 +114,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
boolean isLocal
|
||||
) {
|
||||
super(aClass, context, v, state, parentCodegen);
|
||||
this.classAsmType = typeMapper.mapClass(descriptor);
|
||||
this.classAsmType = getObjectType(typeMapper.classInternalName(descriptor));
|
||||
this.isLocal = isLocal;
|
||||
delegationFieldsInfo = getDelegationFieldsInfo(myClass.getSuperTypeListEntries());
|
||||
}
|
||||
@@ -127,55 +128,47 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
boolean isAbstract = false;
|
||||
boolean isInterface = false;
|
||||
boolean isFinal = false;
|
||||
boolean isStatic;
|
||||
boolean isAnnotation = false;
|
||||
boolean isEnum = false;
|
||||
|
||||
ClassKind kind = descriptor.getKind();
|
||||
|
||||
if (kind == ClassKind.OBJECT) {
|
||||
isStatic = isCompanionObject(descriptor);
|
||||
isFinal = true;
|
||||
Modality modality = descriptor.getModality();
|
||||
|
||||
if (modality == Modality.ABSTRACT || modality == Modality.SEALED) {
|
||||
isAbstract = true;
|
||||
}
|
||||
else {
|
||||
Modality modality = descriptor.getModality();
|
||||
|
||||
if (modality == Modality.ABSTRACT || modality == Modality.SEALED) {
|
||||
isAbstract = true;
|
||||
}
|
||||
if (kind == ClassKind.INTERFACE) {
|
||||
isAbstract = true;
|
||||
isInterface = true;
|
||||
}
|
||||
else if (kind == ClassKind.ANNOTATION_CLASS) {
|
||||
isAbstract = true;
|
||||
isInterface = true;
|
||||
isAnnotation = true;
|
||||
}
|
||||
else if (kind == ClassKind.ENUM_CLASS) {
|
||||
isAbstract = hasAbstractMembers(descriptor);
|
||||
isEnum = true;
|
||||
}
|
||||
|
||||
if (kind == ClassKind.INTERFACE) {
|
||||
isAbstract = true;
|
||||
isInterface = true;
|
||||
}
|
||||
else if (kind == ClassKind.ANNOTATION_CLASS) {
|
||||
isAbstract = true;
|
||||
isInterface = true;
|
||||
isAnnotation = true;
|
||||
}
|
||||
else if (kind == ClassKind.ENUM_CLASS) {
|
||||
isAbstract = hasAbstractMembers(descriptor);
|
||||
isEnum = true;
|
||||
}
|
||||
|
||||
if (modality != Modality.OPEN && !isAbstract) {
|
||||
// Light-class mode: Do not make enum classes final since PsiClass corresponding to enum is expected to be inheritable from
|
||||
isFinal = !(kind == ClassKind.ENUM_CLASS && !state.getClassBuilderMode().generateBodies);
|
||||
}
|
||||
|
||||
isStatic = !descriptor.isInner();
|
||||
if (modality != Modality.OPEN && !isAbstract) {
|
||||
isFinal = kind == ClassKind.OBJECT ||
|
||||
// Light-class mode: Do not make enum classes final since PsiClass corresponding to enum is expected to be inheritable from
|
||||
!(kind == ClassKind.ENUM_CLASS && !state.getClassBuilderMode().generateBodies);
|
||||
}
|
||||
|
||||
int access = 0;
|
||||
|
||||
if (!state.getClassBuilderMode().generateBodies && !DescriptorUtils.isTopLevelDeclaration(descriptor)) {
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES && !DescriptorUtils.isTopLevelDeclaration(descriptor)) {
|
||||
// !ClassBuilderMode.generateBodies means we are generating light classes & looking at a nested or inner class
|
||||
// Light class generation is implemented so that Cls-classes only read bare code of classes,
|
||||
// without knowing whether these classes are inner or not (see ClassStubBuilder.EMPTY_STRATEGY)
|
||||
// Thus we must write full accessibility flags on inner classes in this mode
|
||||
access |= getVisibilityAccessFlag(descriptor);
|
||||
// Same for STATIC
|
||||
if (isStatic) {
|
||||
if (!descriptor.isInner()) {
|
||||
access |= ACC_STATIC;
|
||||
}
|
||||
}
|
||||
@@ -332,7 +325,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
for (String kotlinMarkerInterface : kotlinMarkerInterfaces) {
|
||||
sw.writeInterface();
|
||||
sw.writeAsmType(Type.getObjectType(kotlinMarkerInterface));
|
||||
sw.writeAsmType(getObjectType(kotlinMarkerInterface));
|
||||
sw.writeInterfaceEnd();
|
||||
}
|
||||
|
||||
@@ -1207,9 +1200,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
}
|
||||
else if (descriptor instanceof VariableDescriptor) {
|
||||
if (descriptor.getContainingDeclaration() instanceof ConstructorDescriptor) {
|
||||
ClassDescriptor classDescriptor =
|
||||
(ClassDescriptor) descriptor.getContainingDeclaration().getContainingDeclaration();
|
||||
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
|
||||
if (containingDeclaration instanceof ConstructorDescriptor) {
|
||||
ClassDescriptor classDescriptor = ((ConstructorDescriptor) containingDeclaration).getConstructedClass();
|
||||
if (classDescriptor == ImplementationBodyCodegen.this.descriptor) return;
|
||||
}
|
||||
lookupInContext(descriptor);
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.Synthetic
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
|
||||
class JvmStaticGenerator(
|
||||
val descriptor: FunctionDescriptor,
|
||||
val declarationOrigin: JvmDeclarationOrigin,
|
||||
val state: GenerationState,
|
||||
parentBodyCodegen: ImplementationBodyCodegen
|
||||
) : Function2<ImplementationBodyCodegen, ClassBuilder, Unit> {
|
||||
private val typeMapper = state.typeMapper
|
||||
|
||||
init {
|
||||
parentBodyCodegen.getContext().accessibleDescriptor(JvmCodegenUtil.getDirectMember(descriptor), null)
|
||||
}
|
||||
|
||||
override fun invoke(codegen: ImplementationBodyCodegen, classBuilder: ClassBuilder) {
|
||||
val staticFunctionDescriptor = createStaticFunctionDescriptor(descriptor)
|
||||
|
||||
val originElement = declarationOrigin.element
|
||||
codegen.functionCodegen.generateMethod(
|
||||
Synthetic(originElement, staticFunctionDescriptor),
|
||||
staticFunctionDescriptor,
|
||||
object : FunctionGenerationStrategy.CodegenBased(state) {
|
||||
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
|
||||
val iv = codegen.v
|
||||
val classDescriptor = descriptor.containingDeclaration as ClassDescriptor
|
||||
val singletonValue = StackValue.singleton(classDescriptor, typeMapper)
|
||||
singletonValue.put(singletonValue.type, iv)
|
||||
var index = 0
|
||||
val asmMethod = signature.asmMethod
|
||||
for (paramType in asmMethod.argumentTypes) {
|
||||
iv.load(index, paramType)
|
||||
index += paramType.size
|
||||
}
|
||||
if (descriptor is PropertyAccessorDescriptor) {
|
||||
val propertyValue = codegen.intermediateValueForProperty(descriptor.correspondingProperty, false, null, StackValue.none())
|
||||
if (descriptor is PropertyGetterDescriptor) {
|
||||
propertyValue.put(signature.returnType, iv)
|
||||
}
|
||||
else {
|
||||
propertyValue.store(StackValue.onStack(propertyValue.type), iv, true)
|
||||
}
|
||||
}
|
||||
else {
|
||||
val syntheticOrOriginalMethod = typeMapper.mapToCallableMethod(
|
||||
codegen.context.accessibleDescriptor(descriptor, /* superCallTarget = */ null),
|
||||
false
|
||||
)
|
||||
syntheticOrOriginalMethod.genInvokeInstruction(iv)
|
||||
}
|
||||
iv.areturn(asmMethod.returnType)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if (originElement is KtNamedFunction) {
|
||||
codegen.functionCodegen.generateOverloadsWithDefaultValues(originElement, staticFunctionDescriptor, descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun createStaticFunctionDescriptor(descriptor: FunctionDescriptor): FunctionDescriptor {
|
||||
val memberDescriptor = if (descriptor is PropertyAccessorDescriptor) descriptor.correspondingProperty else descriptor
|
||||
val copies = CodegenUtil.copyFunctions(
|
||||
memberDescriptor,
|
||||
memberDescriptor,
|
||||
descriptor.containingDeclaration.containingDeclaration!!,
|
||||
descriptor.modality,
|
||||
descriptor.visibility,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
false
|
||||
)
|
||||
val staticFunctionDescriptor = copies[descriptor]!!
|
||||
return staticFunctionDescriptor
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.Synthetic
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
|
||||
class JvmStaticInCompanionObjectGenerator(
|
||||
val descriptor: FunctionDescriptor,
|
||||
val declarationOrigin: JvmDeclarationOrigin,
|
||||
val state: GenerationState,
|
||||
parentBodyCodegen: ImplementationBodyCodegen
|
||||
) : Function2<ImplementationBodyCodegen, ClassBuilder, Unit> {
|
||||
private val typeMapper = state.typeMapper
|
||||
|
||||
init {
|
||||
parentBodyCodegen.getContext().accessibleDescriptor(JvmCodegenUtil.getDirectMember(descriptor), null)
|
||||
}
|
||||
|
||||
override fun invoke(codegen: ImplementationBodyCodegen, classBuilder: ClassBuilder) {
|
||||
val staticFunctionDescriptor = createStaticFunctionDescriptor(descriptor)
|
||||
|
||||
val originElement = declarationOrigin.element
|
||||
codegen.functionCodegen.generateMethod(
|
||||
Synthetic(originElement, staticFunctionDescriptor),
|
||||
staticFunctionDescriptor,
|
||||
object : FunctionGenerationStrategy.CodegenBased(state) {
|
||||
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
|
||||
val iv = codegen.v
|
||||
val classDescriptor = descriptor.containingDeclaration as ClassDescriptor
|
||||
val singletonValue = StackValue.singleton(classDescriptor, typeMapper)
|
||||
singletonValue.put(singletonValue.type, iv)
|
||||
var index = 0
|
||||
val asmMethod = signature.asmMethod
|
||||
for (paramType in asmMethod.argumentTypes) {
|
||||
iv.load(index, paramType)
|
||||
index += paramType.size
|
||||
}
|
||||
if (descriptor is PropertyAccessorDescriptor) {
|
||||
val propertyValue = codegen.intermediateValueForProperty(descriptor.correspondingProperty, false, null, StackValue.none())
|
||||
if (descriptor is PropertyGetterDescriptor) {
|
||||
propertyValue.put(signature.returnType, iv)
|
||||
}
|
||||
else {
|
||||
propertyValue.store(StackValue.onStack(propertyValue.type), iv, true)
|
||||
}
|
||||
}
|
||||
else {
|
||||
val syntheticOrOriginalMethod = typeMapper.mapToCallableMethod(
|
||||
codegen.context.accessibleDescriptor(descriptor, /* superCallTarget = */ null),
|
||||
false
|
||||
)
|
||||
syntheticOrOriginalMethod.genInvokeInstruction(iv)
|
||||
}
|
||||
iv.areturn(asmMethod.returnType)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if (originElement is KtNamedFunction) {
|
||||
codegen.functionCodegen.generateOverloadsWithDefaultValues(originElement, staticFunctionDescriptor, descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun createStaticFunctionDescriptor(descriptor: FunctionDescriptor): FunctionDescriptor {
|
||||
val memberDescriptor = if (descriptor is PropertyAccessorDescriptor) descriptor.correspondingProperty else descriptor
|
||||
val copies = CodegenUtil.copyFunctions(
|
||||
memberDescriptor,
|
||||
memberDescriptor,
|
||||
descriptor.containingDeclaration.containingDeclaration!!,
|
||||
descriptor.modality,
|
||||
descriptor.visibility,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
false
|
||||
)
|
||||
val staticFunctionDescriptor = copies[descriptor]!!
|
||||
return staticFunctionDescriptor
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,7 +127,10 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
|
||||
generateBody();
|
||||
|
||||
generateSyntheticParts();
|
||||
if (!(element instanceof KtClassOrObject) ||
|
||||
state.getGenerateDeclaredClassFilter().shouldGenerateClassMembers((KtClassOrObject) element)) {
|
||||
generateSyntheticParts();
|
||||
}
|
||||
|
||||
if (state.getClassBuilderMode().generateMetadata) {
|
||||
generateKotlinMetadataAnnotation();
|
||||
@@ -342,17 +345,19 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
}
|
||||
|
||||
private void writeInnerClass(@NotNull ClassDescriptor innerClass) {
|
||||
writeInnerClass(innerClass, typeMapper, v);
|
||||
if (!ErrorUtils.isError(innerClass)) {
|
||||
writeInnerClass(innerClass, typeMapper, v);
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeInnerClass(@NotNull ClassDescriptor innerClass, @NotNull KotlinTypeMapper typeMapper, @NotNull ClassBuilder v) {
|
||||
DeclarationDescriptor containing = innerClass.getContainingDeclaration();
|
||||
String outerClassInternalName = null;
|
||||
if (containing instanceof ClassDescriptor) {
|
||||
outerClassInternalName = typeMapper.mapClass((ClassDescriptor) containing).getInternalName();
|
||||
outerClassInternalName = typeMapper.classInternalName((ClassDescriptor) containing);
|
||||
}
|
||||
String innerName = innerClass.getName().isSpecial() ? null : innerClass.getName().asString();
|
||||
String innerClassInternalName = typeMapper.mapClass(innerClass).getInternalName();
|
||||
String innerClassInternalName = typeMapper.classInternalName(innerClass);
|
||||
v.visitInnerClass(innerClassInternalName, outerClassInternalName, innerName, calculateInnerClassAccessFlags(innerClass));
|
||||
}
|
||||
|
||||
@@ -499,10 +504,11 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
int indexOfDelegatedProperty = PropertyCodegen.indexOfDelegatedProperty(property);
|
||||
|
||||
StackValue delegateValue = PropertyCodegen.invokeDelegatedPropertyConventionMethodWithReceiver(
|
||||
codegen, typeMapper, provideDelegateResolvedCall, indexOfDelegatedProperty, 1, provideDelegateReceiver);
|
||||
codegen, typeMapper, provideDelegateResolvedCall, indexOfDelegatedProperty, 1,
|
||||
provideDelegateReceiver, propertyDescriptor
|
||||
);
|
||||
|
||||
propValue.store(delegateValue, codegen.v);
|
||||
|
||||
}
|
||||
|
||||
protected boolean shouldInitializeProperty(@NotNull KtProperty property) {
|
||||
@@ -590,7 +596,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
}
|
||||
if (delegatedProperties.isEmpty()) return;
|
||||
|
||||
v.newField(NO_ORIGIN, ACC_PRIVATE | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, JvmAbi.DELEGATED_PROPERTIES_ARRAY_NAME,
|
||||
v.newField(NO_ORIGIN, ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, JvmAbi.DELEGATED_PROPERTIES_ARRAY_NAME,
|
||||
"[" + K_PROPERTY_TYPE, null, null);
|
||||
|
||||
if (!state.getClassBuilderMode().generateBodies) return;
|
||||
|
||||
@@ -176,7 +176,7 @@ class MultifileClassPartCodegen(
|
||||
}
|
||||
|
||||
val serializer = DescriptorSerializer.createTopLevel(JvmSerializerExtension(v.serializationBindings, state))
|
||||
val packageProto = serializer.packagePartProto(members).build()
|
||||
val packageProto = serializer.packagePartProto(packageFragment.fqName, members).build()
|
||||
|
||||
val extraFlags = if (shouldGeneratePartHierarchy) JvmAnnotationNames.METADATA_MULTIFILE_PARTS_INHERIT_FLAG else 0
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ public class PackagePartCodegen extends MemberCodegen<KtFile> {
|
||||
|
||||
final DescriptorSerializer serializer =
|
||||
DescriptorSerializer.createTopLevel(new JvmSerializerExtension(v.getSerializationBindings(), state));
|
||||
final ProtoBuf.Package packageProto = serializer.packagePartProto(members).build();
|
||||
final ProtoBuf.Package packageProto = serializer.packagePartProto(element.getPackageFqName(), members).build();
|
||||
|
||||
WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.FILE_FACADE, 0, new Function1<AnnotationVisitor, Unit>() {
|
||||
@Override
|
||||
|
||||
@@ -188,7 +188,7 @@ public class PropertyCodegen {
|
||||
if (isCompanionObject(descriptor.getContainingDeclaration())) return true;
|
||||
|
||||
// Non-const properties from multifile classes have accessors regardless of visibility
|
||||
if (!descriptor.isConst() && JvmFileClassUtilKt.isInsideJvmMultifileClassFile(declaration)) return true;
|
||||
if (isNonConstTopLevelPropertyInMultifileClass(declaration, descriptor)) return true;
|
||||
|
||||
// Private class properties have accessors only in cases when those accessors are non-trivial
|
||||
if (Visibilities.isPrivate(descriptor.getVisibility())) {
|
||||
@@ -198,6 +198,15 @@ public class PropertyCodegen {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isNonConstTopLevelPropertyInMultifileClass(
|
||||
@NotNull KtProperty declaration,
|
||||
@NotNull PropertyDescriptor descriptor
|
||||
) {
|
||||
return !descriptor.isConst() &&
|
||||
descriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor &&
|
||||
JvmFileClassUtilKt.isInsideJvmMultifileClassFile(declaration);
|
||||
}
|
||||
|
||||
private static boolean areAccessorsNeededForPrimaryConstructorProperty(
|
||||
@NotNull PropertyDescriptor descriptor
|
||||
) {
|
||||
@@ -534,7 +543,7 @@ public class PropertyCodegen {
|
||||
StackValue.Property receiver = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
|
||||
return invokeDelegatedPropertyConventionMethodWithReceiver(
|
||||
codegen, typeMapper, resolvedCall, indexInPropertyMetadataArray, propertyMetadataArgumentIndex,
|
||||
receiver
|
||||
receiver, propertyDescriptor
|
||||
);
|
||||
}
|
||||
|
||||
@@ -544,9 +553,12 @@ public class PropertyCodegen {
|
||||
@NotNull ResolvedCall<FunctionDescriptor> resolvedCall,
|
||||
final int indexInPropertyMetadataArray,
|
||||
int propertyMetadataArgumentIndex,
|
||||
@Nullable StackValue receiver
|
||||
@Nullable StackValue receiver,
|
||||
@NotNull PropertyDescriptor propertyDescriptor
|
||||
) {
|
||||
final Type owner = getDelegatedPropertyMetadataOwner(codegen, typeMapper);
|
||||
final Type owner = JvmAbi.isPropertyWithBackingFieldInOuterClass(propertyDescriptor) ?
|
||||
codegen.getState().getTypeMapper().mapOwner(propertyDescriptor) :
|
||||
getDelegatedPropertyMetadataOwner(codegen, typeMapper);
|
||||
|
||||
codegen.tempVariables.put(
|
||||
resolvedCall.getCall().getValueArguments().get(propertyMetadataArgumentIndex).asElement(),
|
||||
|
||||
@@ -34,7 +34,7 @@ data class SourceInfo(val source: String, val pathOrCleanFQN: String, val linesI
|
||||
val isTopLevel = element is KtFile || (element is KtNamedFunction && element.getParent() is KtFile)
|
||||
val cleanedClassFqName = if (!isTopLevel) internalClassName else internalClassName.substringBefore('$')
|
||||
|
||||
return SourceInfo(element.getContainingKtFile().name, cleanedClassFqName, lineNumbers!!)
|
||||
return SourceInfo(element.containingKtFile.name, cleanedClassFqName, lineNumbers!!)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
@@ -281,60 +282,29 @@ public abstract class StackValue {
|
||||
}
|
||||
|
||||
private static void box(Type type, Type toType, InstructionAdapter v) {
|
||||
if (type == Type.BYTE_TYPE || toType.getInternalName().equals(NULLABLE_BYTE_TYPE_NAME) && type == Type.INT_TYPE) {
|
||||
v.cast(type, Type.BYTE_TYPE);
|
||||
v.invokestatic(NULLABLE_BYTE_TYPE_NAME, "valueOf", "(B)L" + NULLABLE_BYTE_TYPE_NAME + ";", false);
|
||||
}
|
||||
else if (type == Type.SHORT_TYPE || toType.getInternalName().equals(NULLABLE_SHORT_TYPE_NAME) && type == Type.INT_TYPE) {
|
||||
v.cast(type, Type.SHORT_TYPE);
|
||||
v.invokestatic(NULLABLE_SHORT_TYPE_NAME, "valueOf", "(S)L" + NULLABLE_SHORT_TYPE_NAME + ";", false);
|
||||
}
|
||||
else if (type == Type.LONG_TYPE || toType.getInternalName().equals(NULLABLE_LONG_TYPE_NAME) && type == Type.INT_TYPE) {
|
||||
v.cast(type, Type.LONG_TYPE);
|
||||
v.invokestatic(NULLABLE_LONG_TYPE_NAME, "valueOf", "(J)L" + NULLABLE_LONG_TYPE_NAME + ";", false);
|
||||
}
|
||||
else if (type == Type.INT_TYPE) {
|
||||
v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
|
||||
}
|
||||
else if (type == Type.BOOLEAN_TYPE) {
|
||||
v.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
|
||||
}
|
||||
else if (type == Type.CHAR_TYPE) {
|
||||
v.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
|
||||
}
|
||||
else if (type == Type.FLOAT_TYPE) {
|
||||
v.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
|
||||
}
|
||||
else if (type == Type.DOUBLE_TYPE) {
|
||||
v.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
|
||||
if (type == Type.INT_TYPE) {
|
||||
if (toType.getInternalName().equals(NULLABLE_BYTE_TYPE_NAME)) {
|
||||
type = Type.BYTE_TYPE;
|
||||
}
|
||||
else if (toType.getInternalName().equals(NULLABLE_SHORT_TYPE_NAME)) {
|
||||
type = Type.SHORT_TYPE;
|
||||
}
|
||||
else if (toType.getInternalName().equals(NULLABLE_LONG_TYPE_NAME)) {
|
||||
type = Type.LONG_TYPE;
|
||||
}
|
||||
v.cast(Type.INT_TYPE, type);
|
||||
}
|
||||
|
||||
Type boxedType = AsmUtil.boxType(type);
|
||||
if (boxedType == type) return;
|
||||
|
||||
v.invokestatic(boxedType.getInternalName(), "valueOf", Type.getMethodDescriptor(boxedType, type), false);
|
||||
coerce(boxedType, toType, v);
|
||||
}
|
||||
|
||||
private static void unbox(Type type, InstructionAdapter v) {
|
||||
if (type == Type.INT_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "intValue", "()I", false);
|
||||
}
|
||||
else if (type == Type.BOOLEAN_TYPE) {
|
||||
v.invokevirtual("java/lang/Boolean", "booleanValue", "()Z", false);
|
||||
}
|
||||
else if (type == Type.CHAR_TYPE) {
|
||||
v.invokevirtual("java/lang/Character", "charValue", "()C", false);
|
||||
}
|
||||
else if (type == Type.SHORT_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "shortValue", "()S", false);
|
||||
}
|
||||
else if (type == Type.LONG_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "longValue", "()J", false);
|
||||
}
|
||||
else if (type == Type.BYTE_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "byteValue", "()B", false);
|
||||
}
|
||||
else if (type == Type.FLOAT_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "floatValue", "()F", false);
|
||||
}
|
||||
else if (type == Type.DOUBLE_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "doubleValue", "()D", false);
|
||||
}
|
||||
private static void unbox(Type methodOwner, Type type, InstructionAdapter v) {
|
||||
assert isPrimitive(type) : "Unboxing should be performed to primitive type, but " + type.getClassName();
|
||||
v.invokevirtual(methodOwner.getInternalName(), type.getClassName() + "Value", "()" + type.getDescriptor(), false);
|
||||
}
|
||||
|
||||
protected void coerceTo(@NotNull Type toType, @NotNull InstructionAdapter v) {
|
||||
@@ -372,23 +342,12 @@ public abstract class StackValue {
|
||||
}
|
||||
}
|
||||
else if (toType.getSort() == Type.ARRAY) {
|
||||
if (fromType.getSort() == Type.ARRAY &&
|
||||
fromType.getElementType().equals(AsmTypes.JAVA_CLASS_TYPE) && toType.equals(K_CLASS_ARRAY_TYPE)) {
|
||||
wrapJavaClassesIntoKClasses(v);
|
||||
}
|
||||
else {
|
||||
v.checkcast(toType);
|
||||
}
|
||||
v.checkcast(toType);
|
||||
}
|
||||
else if (toType.getSort() == Type.OBJECT) {
|
||||
if (fromType.getSort() == Type.OBJECT || fromType.getSort() == Type.ARRAY) {
|
||||
if (!toType.equals(OBJECT_TYPE)) {
|
||||
if (fromType.equals(AsmTypes.JAVA_CLASS_TYPE) && toType.equals(AsmTypes.K_CLASS_TYPE)) {
|
||||
wrapJavaClassIntoKClass(v);
|
||||
}
|
||||
else {
|
||||
v.checkcast(toType);
|
||||
}
|
||||
v.checkcast(toType);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -396,20 +355,29 @@ public abstract class StackValue {
|
||||
}
|
||||
}
|
||||
else if (fromType.getSort() == Type.OBJECT) {
|
||||
//toType is primitive here
|
||||
Type unboxedType = unboxPrimitiveTypeOrNull(fromType);
|
||||
if (unboxedType != null) {
|
||||
unbox(unboxedType, v);
|
||||
unbox(fromType, unboxedType, v);
|
||||
coerce(unboxedType, toType, v);
|
||||
}
|
||||
else {
|
||||
Type numberType = getType(Number.class);
|
||||
if (toType.getSort() == Type.BOOLEAN || (toType.getSort() == Type.CHAR && !numberType.equals(fromType))) {
|
||||
coerce(fromType, boxType(toType), v);
|
||||
else if (toType.getSort() == Type.BOOLEAN) {
|
||||
coerce(fromType, BOOLEAN_WRAPPER_TYPE, v);
|
||||
unbox(BOOLEAN_WRAPPER_TYPE, Type.BOOLEAN_TYPE, v);
|
||||
}
|
||||
else if (toType.getSort() == Type.CHAR) {
|
||||
if (fromType.equals(NUMBER_TYPE)) {
|
||||
unbox(NUMBER_TYPE, Type.INT_TYPE, v);
|
||||
v.visitInsn(Opcodes.I2C);
|
||||
}
|
||||
else {
|
||||
coerce(fromType, numberType, v);
|
||||
coerce(fromType, CHARACTER_WRAPPER_TYPE, v);
|
||||
unbox(CHARACTER_WRAPPER_TYPE, Type.CHAR_TYPE, v);
|
||||
}
|
||||
unbox(toType, v);
|
||||
}
|
||||
else {
|
||||
coerce(fromType, NUMBER_TYPE, v);
|
||||
unbox(NUMBER_TYPE, toType, v);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -883,7 +851,7 @@ public abstract class StackValue {
|
||||
newReceiver.put(newReceiver.type, v);
|
||||
callGenerator.processAndPutHiddenParameters(false);
|
||||
|
||||
defaultArgs = generator.generate(valueArguments, valueArguments);
|
||||
defaultArgs = generator.generate(valueArguments, valueArguments, call.getResultingDescriptor());
|
||||
}
|
||||
|
||||
private ArgumentGenerator createArgumentGenerator() {
|
||||
@@ -1211,7 +1179,20 @@ public abstract class StackValue {
|
||||
else {
|
||||
getter.genInvokeInstruction(v);
|
||||
}
|
||||
coerce(getter.getReturnType(), type, v);
|
||||
|
||||
Type typeOfValueOnStack = getter.getReturnType();
|
||||
if (DescriptorUtils.isAnnotationClass(descriptor.getContainingDeclaration())) {
|
||||
if (this.type.equals(K_CLASS_TYPE)) {
|
||||
wrapJavaClassIntoKClass(v);
|
||||
typeOfValueOnStack = K_CLASS_TYPE;
|
||||
}
|
||||
else if (this.type.equals(K_CLASS_ARRAY_TYPE)) {
|
||||
wrapJavaClassesIntoKClasses(v);
|
||||
typeOfValueOnStack = K_CLASS_ARRAY_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
coerce(typeOfValueOnStack, type, v);
|
||||
|
||||
KotlinType returnType = descriptor.getReturnType();
|
||||
if (returnType != null && KotlinBuiltIns.isNothing(returnType)) {
|
||||
@@ -1378,9 +1359,7 @@ public abstract class StackValue {
|
||||
default:
|
||||
PrimitiveType primitiveType = AsmUtil.asmPrimitiveTypeToLangPrimitiveType(type);
|
||||
if (primitiveType == null) throw new UnsupportedOperationException();
|
||||
|
||||
String typeName = primitiveType.getTypeName().getIdentifier();
|
||||
return Type.getObjectType(REF_TYPE_PREFIX + typeName + "Ref");
|
||||
return sharedTypeForPrimitive(primitiveType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getParentCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.overriddenTreeAsSequence
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
import java.util.*
|
||||
|
||||
class BridgeForBuiltinSpecial<out Signature : Any>(
|
||||
@@ -76,7 +75,7 @@ object BuiltinSpecialBridgesUtil {
|
||||
else null
|
||||
|
||||
val commonBridges = reachableDeclarations.mapTo(LinkedHashSet<Signature>(), signatureByDescriptor)
|
||||
commonBridges.removeAll(specialBridgesSignaturesInSuperClass + specialBridge?.from.singletonOrEmptyList())
|
||||
commonBridges.removeAll(specialBridgesSignaturesInSuperClass + listOfNotNull(specialBridge?.from))
|
||||
|
||||
if (fake) {
|
||||
for (overridden in function.overriddenDescriptors.map { it.original }) {
|
||||
|
||||
@@ -40,7 +40,7 @@ private fun Iterable<PackageParts>.addCompiledParts(state: GenerationState): Lis
|
||||
val incrementalCache = state.incrementalCacheForThisTarget ?: return this.toList()
|
||||
val moduleMappingData = incrementalCache.getModuleMappingData() ?: return this.toList()
|
||||
|
||||
val mapping = ModuleMapping.create(moduleMappingData, "<incremental>")
|
||||
val mapping = ModuleMapping.create(moduleMappingData, "<incremental>", state.deserializationConfiguration)
|
||||
|
||||
incrementalCache.getObsoletePackageParts().forEach { internalName ->
|
||||
val qualifier = internalName.substringBeforeLast('/', "").replace('/', '.')
|
||||
|
||||
@@ -42,7 +42,6 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
@@ -72,7 +71,7 @@ class CoroutineCodegen private constructor(
|
||||
// protected fun doResume(result, throwable)
|
||||
private val doResumeDescriptor =
|
||||
SimpleFunctionDescriptorImpl.create(
|
||||
classDescriptor, Annotations.EMPTY, Name.identifier("doResume"), CallableMemberDescriptor.Kind.DECLARATION,
|
||||
classDescriptor, Annotations.EMPTY, Name.identifier(DO_RESUME_METHOD_NAME), CallableMemberDescriptor.Kind.DECLARATION,
|
||||
funDescriptor.source
|
||||
).apply doResume@{
|
||||
initialize(
|
||||
@@ -289,8 +288,8 @@ class CoroutineCodegen private constructor(
|
||||
}
|
||||
|
||||
private fun allFunctionParameters() =
|
||||
originalSuspendFunctionDescriptor.extensionReceiverParameter.singletonOrEmptyList() +
|
||||
originalSuspendFunctionDescriptor.valueParameters.orEmpty()
|
||||
listOfNotNull(originalSuspendFunctionDescriptor.extensionReceiverParameter) +
|
||||
originalSuspendFunctionDescriptor.valueParameters.orEmpty()
|
||||
|
||||
private fun ParameterDescriptor.getFieldInfoForCoroutineLambdaParameter() =
|
||||
createHiddenFieldInfo(type, COROUTINE_LAMBDA_PARAMETER_PREFIX + (this.safeAs<ValueParameterDescriptor>()?.index ?: ""))
|
||||
@@ -328,6 +327,11 @@ class CoroutineCodegen private constructor(
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun shouldCreateByLambda(
|
||||
originalSuspendLambdaDescriptor: CallableDescriptor,
|
||||
declaration: KtElement): Boolean {
|
||||
return (declaration is KtFunctionLiteral && originalSuspendLambdaDescriptor.isSuspendLambda)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun createByLambda(
|
||||
@@ -336,8 +340,7 @@ class CoroutineCodegen private constructor(
|
||||
declaration: KtElement,
|
||||
classBuilder: ClassBuilder
|
||||
): ClosureCodegen? {
|
||||
if (declaration !is KtFunctionLiteral) return null
|
||||
if (!originalSuspendLambdaDescriptor.isSuspendLambda) return null
|
||||
if (!shouldCreateByLambda(originalSuspendLambdaDescriptor, declaration)) return null
|
||||
|
||||
return CoroutineCodegen(
|
||||
expressionCodegen,
|
||||
|
||||
@@ -294,7 +294,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
get() {
|
||||
assert(suspensionCallEnd.next is LabelNode) {
|
||||
"Next instruction after ${this} should be a label, but " +
|
||||
"${suspensionCallEnd.next.javaClass}/${suspensionCallEnd.next.opcode} was found"
|
||||
"${suspensionCallEnd.next::class.java}/${suspensionCallEnd.next.opcode} was found"
|
||||
}
|
||||
|
||||
return suspensionCallEnd.next as LabelNode
|
||||
@@ -421,7 +421,7 @@ private fun InstructionAdapter.generateResumeWithExceptionCheck() {
|
||||
|
||||
private fun Type.fieldNameForVar(index: Int) = descriptor.first() + "$" + index
|
||||
|
||||
private fun withInstructionAdapter(block: InstructionAdapter.() -> Unit): InsnList {
|
||||
inline fun withInstructionAdapter(block: InstructionAdapter.() -> Unit): InsnList {
|
||||
val tmpMethodNode = MethodNode()
|
||||
|
||||
InstructionAdapter(tmpMethodNode).apply(block)
|
||||
|
||||
@@ -217,7 +217,7 @@ private class VarExpectedTypeFrame(maxLocals: Int) : VarFrame<VarExpectedTypeFra
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other?.javaClass != javaClass) return false
|
||||
if (other == null || other::class.java != this::class.java) return false
|
||||
|
||||
other as VarExpectedTypeFrame
|
||||
|
||||
|
||||
@@ -66,7 +66,6 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
createClassReader().accept(new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) {
|
||||
@Override
|
||||
public void visit(int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) {
|
||||
InlineCodegenUtil.assertVersionNotGreaterThanGeneratedOne(version, name, inliningContext.state);
|
||||
classBuilder.defineClass(null, version, access, name, signature, superName, interfaces);
|
||||
if(CoroutineCodegenUtilKt.COROUTINE_IMPL_ASM_TYPE.getInternalName().equals(superName)) {
|
||||
inliningContext.setContinuation(true);
|
||||
@@ -141,12 +140,12 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
List<CapturedParamInfo> additionalFakeParams =
|
||||
extractParametersMappingAndPatchConstructor(constructor, allCapturedParamBuilder, constructorParamBuilder,
|
||||
transformationInfo, parentRemapper);
|
||||
List<MethodVisitor> deferringMethods = new ArrayList<MethodVisitor>();
|
||||
List<DeferredMethodVisitor> deferringMethods = new ArrayList<DeferredMethodVisitor>();
|
||||
|
||||
generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, parentRemapper, additionalFakeParams);
|
||||
|
||||
for (MethodNode next : methodsToTransform) {
|
||||
MethodVisitor deferringVisitor = newMethod(classBuilder, next);
|
||||
DeferredMethodVisitor deferringVisitor = newMethod(classBuilder, next);
|
||||
InlineResult funResult =
|
||||
inlineMethodAndUpdateGlobalResult(parentRemapper, deferringVisitor, next, allCapturedParamBuilder, false);
|
||||
|
||||
@@ -161,7 +160,8 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
deferringMethods.add(deferringVisitor);
|
||||
}
|
||||
|
||||
for (MethodVisitor method : deferringMethods) {
|
||||
for (DeferredMethodVisitor method : deferringMethods) {
|
||||
InlineCodegenUtil.removeFinallyMarkers(method.getIntermediate());
|
||||
method.visitEnd();
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
//TODO for inline method make public class
|
||||
transformationInfo.setNewConstructorDescriptor(constructorDescriptor);
|
||||
MethodVisitor constructorVisitor = classBuilder.newMethod(
|
||||
NO_ORIGIN, AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY
|
||||
NO_ORIGIN, constructor.access, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY
|
||||
);
|
||||
|
||||
final Label newBodyStartLabel = new Label();
|
||||
@@ -311,8 +311,9 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
}
|
||||
|
||||
MethodNode intermediateMethodNode =
|
||||
new MethodNode(AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
new MethodNode(constructor.access, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
inlineMethodAndUpdateGlobalResult(parentRemapper, intermediateMethodNode, constructor, constructorInlineBuilder, true);
|
||||
InlineCodegenUtil.removeFinallyMarkers(intermediateMethodNode);
|
||||
|
||||
AbstractInsnNode first = intermediateMethodNode.instructions.getFirst();
|
||||
final Label oldStartLabel = first instanceof LabelNode ? ((LabelNode) first).getLabel() : null;
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
@@ -202,7 +203,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
MethodNode node = nodeAndSmap != null ? nodeAndSmap.getNode() : null;
|
||||
throw new CompilationException(
|
||||
"Couldn't inline method call '" + functionDescriptor.getName() + "' into\n" +
|
||||
contextDescriptor + "\n" +
|
||||
DescriptorRenderer.DEBUG_TEXT.render(contextDescriptor) + "\n" +
|
||||
(element != null ? element.getText() : "<no source>") +
|
||||
(generateNodeText ? ("\nCause: " + InlineCodegenUtil.getNodeText(node)) : ""),
|
||||
e, callElement
|
||||
@@ -321,7 +322,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
}
|
||||
});
|
||||
|
||||
return InlineCodegenUtil.getMethodNode(bytes, asmMethod.getName(), asmMethod.getDescriptor(), classId, state);
|
||||
return InlineCodegenUtil.getMethodNode(bytes, asmMethod.getName(), asmMethod.getDescriptor(), classId);
|
||||
}
|
||||
|
||||
assert callableDescriptor instanceof DeserializedCallableMemberDescriptor : "Not a deserialized function or proper: " + callableDescriptor;
|
||||
@@ -348,7 +349,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
});
|
||||
|
||||
|
||||
return InlineCodegenUtil.getMethodNode(bytes, asmMethod.getName(), asmMethod.getDescriptor(), containerId, state);
|
||||
return InlineCodegenUtil.getMethodNode(bytes, asmMethod.getName(), asmMethod.getDescriptor(), containerId);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -466,7 +467,9 @@ public class InlineCodegen extends CallGenerator {
|
||||
adapter, infos, ((StackValue.Local) remapper.remap(parameters.getArgsSizeOnStack() + 1).value).index
|
||||
);
|
||||
removeStaticInitializationTrigger(adapter);
|
||||
removeFinallyMarkers(adapter);
|
||||
if (!InlineCodegenUtil.isFinallyMarkerRequired(codegen.getContext())) {
|
||||
InlineCodegenUtil.removeFinallyMarkers(adapter);
|
||||
}
|
||||
|
||||
adapter.accept(new MethodBodyVisitor(codegen.v));
|
||||
|
||||
@@ -1024,25 +1027,6 @@ public class InlineCodegen extends CallGenerator {
|
||||
//processor.substituteLocalVarTable(intoNode);
|
||||
}
|
||||
|
||||
private void removeFinallyMarkers(@NotNull MethodNode intoNode) {
|
||||
if (InlineCodegenUtil.isFinallyMarkerRequired(codegen.getContext())) return;
|
||||
|
||||
InsnList instructions = intoNode.instructions;
|
||||
AbstractInsnNode curInstr = instructions.getFirst();
|
||||
while (curInstr != null) {
|
||||
if (InlineCodegenUtil.isFinallyMarker(curInstr)) {
|
||||
AbstractInsnNode marker = curInstr;
|
||||
//just to assert
|
||||
getConstant(marker.getPrevious());
|
||||
curInstr = curInstr.getNext();
|
||||
instructions.remove(marker.getPrevious());
|
||||
instructions.remove(marker);
|
||||
continue;
|
||||
}
|
||||
curInstr = curInstr.getNext();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap, @NotNull SourceMapper parent) {
|
||||
return new NestedSourceMapper(parent, nodeAndSmap.getSortedRanges(), nodeAndSmap.getClassSMAP().getSourceInfo());
|
||||
|
||||
@@ -39,7 +39,7 @@ import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.fileClasses.FileClasses;
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmVirtualFileFinder;
|
||||
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
@@ -52,6 +52,7 @@ import org.jetbrains.kotlin.util.OperatorNameConventions;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.jetbrains.org.objectweb.asm.tree.*;
|
||||
import org.jetbrains.org.objectweb.asm.util.Printer;
|
||||
import org.jetbrains.org.objectweb.asm.util.Textifier;
|
||||
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
|
||||
|
||||
@@ -81,7 +82,9 @@ public class InlineCodegenUtil {
|
||||
private static final String INLINE_MARKER_AFTER_METHOD_NAME = "afterInlineCall";
|
||||
private static final String INLINE_MARKER_FINALLY_START = "finallyStart";
|
||||
private static final String INLINE_MARKER_FINALLY_END = "finallyEnd";
|
||||
public static final String SPECIAL_TRANSFORMATION_NAME = "$special";
|
||||
public static final String INLINE_TRANSFORMATION_SUFFIX = "$inlined";
|
||||
public static final String INLINE_CALL_TRANSFORMATION_SUFFIX = "$" + INLINE_TRANSFORMATION_SUFFIX;
|
||||
public static final String INLINE_FUN_THIS_0_SUFFIX = "$inline_fun";
|
||||
public static final String INLINE_FUN_VAR_SUFFIX = "$iv";
|
||||
|
||||
@@ -90,8 +93,7 @@ public class InlineCodegenUtil {
|
||||
byte[] classData,
|
||||
final String methodName,
|
||||
final String methodDescriptor,
|
||||
ClassId classId,
|
||||
final @NotNull GenerationState state
|
||||
ClassId classId
|
||||
) {
|
||||
ClassReader cr = new ClassReader(classData);
|
||||
final MethodNode[] node = new MethodNode[1];
|
||||
@@ -101,10 +103,6 @@ public class InlineCodegenUtil {
|
||||
lines[1] = Integer.MIN_VALUE;
|
||||
//noinspection PointlessBitwiseExpression
|
||||
cr.accept(new ClassVisitor(API) {
|
||||
@Override
|
||||
public void visit(int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) {
|
||||
assertVersionNotGreaterThanGeneratedOne(version, name, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSource(String source, String debug) {
|
||||
@@ -149,16 +147,6 @@ public class InlineCodegenUtil {
|
||||
return new SMAPAndMethodNode(node[0], smap);
|
||||
}
|
||||
|
||||
public static void assertVersionNotGreaterThanGeneratedOne(int version, String internalName, @NotNull GenerationState state) {
|
||||
// TODO: report a proper diagnostic
|
||||
if (version > state.getClassFileVersion() && !"true".equals(System.getProperty("kotlin.skip.bytecode.version.check"))) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot inline bytecode of class " + internalName + " which has version " + version + ". " +
|
||||
"This compiler can only inline Java 1.6 bytecode (version " + Opcodes.V1_6 + ")"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static void initDefaultSourceMappingIfNeeded(
|
||||
@NotNull CodegenContext context, @NotNull MemberCodegen codegen, @NotNull GenerationState state
|
||||
) {
|
||||
@@ -177,7 +165,7 @@ public class InlineCodegenUtil {
|
||||
|
||||
@Nullable
|
||||
public static VirtualFile findVirtualFile(@NotNull GenerationState state, @NotNull ClassId classId) {
|
||||
return JvmVirtualFileFinder.SERVICE.getInstance(state.getProject()).findVirtualFileWithHeader(classId);
|
||||
return VirtualFileFinder.SERVICE.getInstance(state.getProject()).findVirtualFileWithHeader(classId);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -403,6 +391,11 @@ public class InlineCodegenUtil {
|
||||
return sw.toString().trim();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getInsnOpcodeText(@Nullable AbstractInsnNode node) {
|
||||
return node == null ? "null" : Printer.OPCODES[node.getOpcode()];
|
||||
}
|
||||
|
||||
@NotNull
|
||||
/* package */ static ClassReader buildClassReaderByInternalName(@NotNull GenerationState state, @NotNull String internalName) {
|
||||
//try to find just compiled classes then in dependencies
|
||||
@@ -464,6 +457,23 @@ public class InlineCodegenUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeFinallyMarkers(@NotNull MethodNode intoNode) {
|
||||
InsnList instructions = intoNode.instructions;
|
||||
AbstractInsnNode curInstr = instructions.getFirst();
|
||||
while (curInstr != null) {
|
||||
if (isFinallyMarker(curInstr)) {
|
||||
AbstractInsnNode marker = curInstr;
|
||||
//just to assert
|
||||
getConstant(marker.getPrevious());
|
||||
curInstr = curInstr.getNext();
|
||||
instructions.remove(marker.getPrevious());
|
||||
instructions.remove(marker);
|
||||
continue;
|
||||
}
|
||||
curInstr = curInstr.getNext();
|
||||
}
|
||||
}
|
||||
|
||||
public static void addInlineMarker(@NotNull InstructionAdapter v, boolean isStartNotEnd) {
|
||||
v.visitMethodInsn(
|
||||
Opcodes.INVOKESTATIC, INLINE_MARKER_CLASS_NAME,
|
||||
|
||||
@@ -252,6 +252,7 @@ public class MethodInliner {
|
||||
//TODO add skipped this and receiver
|
||||
InlineResult lambdaResult = inliner.doInline(this.mv, remapper, true, info, invokeCall.finallyDepthShift);
|
||||
result.mergeWithNotChangeInfo(lambdaResult);
|
||||
result.getReifiedTypeParametersUsages().mergeAll(lambdaResult.getReifiedTypeParametersUsages());
|
||||
|
||||
//return value boxing/unboxing
|
||||
Method bridge = typeMapper.mapAsmMethod(ClosureCodegen.getErasedInvokeFunction(info.getFunctionDescriptor()));
|
||||
@@ -463,6 +464,7 @@ public class MethodInliner {
|
||||
Map<Integer, LambdaInfo> lambdaMapping = new HashMap<Integer, LambdaInfo>();
|
||||
|
||||
int offset = 0;
|
||||
boolean capturesAnonymousObjectThatMustBeRegenerated = false;
|
||||
for (int i = 0; i < paramCount; i++) {
|
||||
SourceValue sourceValue = frame.getStack(firstParameterIndex + i);
|
||||
LambdaInfo lambdaInfo = MethodInlinerUtilKt.getLambdaIfExistsAndMarkInstructions(
|
||||
@@ -471,15 +473,25 @@ public class MethodInliner {
|
||||
if (lambdaInfo != null) {
|
||||
lambdaMapping.put(offset, lambdaInfo);
|
||||
}
|
||||
else if (i < argTypes.length && isAnonymousClassThatMustBeRegenerated(argTypes[i])) {
|
||||
capturesAnonymousObjectThatMustBeRegenerated = true;
|
||||
}
|
||||
|
||||
offset += i == 0 ? 1 : argTypes[i - 1].getSize();
|
||||
}
|
||||
|
||||
transformations.add(
|
||||
buildConstructorInvocation(owner, desc, lambdaMapping, awaitClassReification)
|
||||
buildConstructorInvocation(
|
||||
owner, desc, lambdaMapping, awaitClassReification, capturesAnonymousObjectThatMustBeRegenerated
|
||||
)
|
||||
);
|
||||
awaitClassReification = false;
|
||||
}
|
||||
else if (inliningContext.isInliningLambda && ReifiedTypeInliner.Companion.isOperationReifiedMarker(cur)) {
|
||||
ReificationArgument reificationArgument = ReifiedTypeInlinerKt.getReificationArgument((MethodInsnNode) cur);
|
||||
String parameterName = reificationArgument.getParameterName();
|
||||
result.getReifiedTypeParametersUsages().addUsedReifiedParameter(parameterName);
|
||||
}
|
||||
}
|
||||
else if (cur.getOpcode() == Opcodes.GETSTATIC) {
|
||||
FieldInsnNode fieldInsnNode = (FieldInsnNode) cur;
|
||||
@@ -538,6 +550,12 @@ public class MethodInliner {
|
||||
return node;
|
||||
}
|
||||
|
||||
private boolean isAnonymousClassThatMustBeRegenerated(@Nullable Type type) {
|
||||
if (type == null || type.getSort() != Type.OBJECT) return false;
|
||||
AnonymousObjectTransformationInfo info = inliningContext.findAnonymousObjectTransformationInfo(type.getInternalName());
|
||||
return info != null && info.shouldRegenerate(true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Frame<SourceValue>[] analyzeMethodNodeBeforeInline(@NotNull MethodNode node) {
|
||||
try {
|
||||
@@ -584,7 +602,8 @@ public class MethodInliner {
|
||||
@NotNull String anonymousType,
|
||||
@NotNull String desc,
|
||||
@NotNull Map<Integer, LambdaInfo> lambdaMapping,
|
||||
boolean needReification
|
||||
boolean needReification,
|
||||
boolean capturesAnonymousObjectThatMustBeRegenerated
|
||||
) {
|
||||
boolean memoizeAnonymousObject = inliningContext.findAnonymousObjectTransformationInfo(anonymousType) == null;
|
||||
|
||||
@@ -594,7 +613,8 @@ public class MethodInliner {
|
||||
isAlreadyRegenerated(anonymousType),
|
||||
desc,
|
||||
false,
|
||||
inliningContext.nameGenerator
|
||||
inliningContext.nameGenerator,
|
||||
capturesAnonymousObjectThatMustBeRegenerated
|
||||
);
|
||||
|
||||
if (memoizeAnonymousObject) {
|
||||
|
||||
@@ -66,7 +66,6 @@ class WhenMappingTransformer(
|
||||
val fieldNode = transformationInfo.fieldNode
|
||||
classReader.accept(object : ClassVisitor(InlineCodegenUtil.API, classBuilder.visitor) {
|
||||
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<String>) {
|
||||
InlineCodegenUtil.assertVersionNotGreaterThanGeneratedOne(version, name, state)
|
||||
classBuilder.defineClass(null, version, access, name, signature, superName, interfaces)
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,5 @@ internal class Parameters(val parameters: List<ParameterInfo>) : Iterable<Parame
|
||||
}
|
||||
|
||||
val capturedTypes: List<Type>
|
||||
get() = captured.map {
|
||||
it.getType()
|
||||
}
|
||||
get() = captured.map(CapturedParamInfo::getType)
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?)
|
||||
const val REIFIED_OPERATION_MARKER_METHOD_NAME = "reifiedOperationMarker"
|
||||
const val NEED_CLASS_REIFICATION_MARKER_METHOD_NAME = "needClassReification"
|
||||
|
||||
private fun isOperationReifiedMarker(insn: AbstractInsnNode) =
|
||||
fun isOperationReifiedMarker(insn: AbstractInsnNode) =
|
||||
isReifiedMarker(insn) { it == REIFIED_OPERATION_MARKER_METHOD_NAME }
|
||||
|
||||
private fun isReifiedMarker(insn: AbstractInsnNode, namePredicate: (String) -> Boolean): Boolean {
|
||||
@@ -247,7 +247,7 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?)
|
||||
}
|
||||
}
|
||||
|
||||
private val MethodInsnNode.reificationArgument: ReificationArgument?
|
||||
val MethodInsnNode.reificationArgument: ReificationArgument?
|
||||
get() {
|
||||
val prev = previous!!
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ class SMAPBuilder(
|
||||
private fun generateDebugStrata(realMappings: List<FileMapping>): String {
|
||||
val combinedMapping = FileMapping(source, path)
|
||||
realMappings.forEach { fileMapping ->
|
||||
fileMapping.lineMappings.filter { it.callSiteMarker != null }.forEach { (source, dest, range, callSiteMarker) ->
|
||||
fileMapping.lineMappings.filter { it.callSiteMarker != null }.forEach { (_, dest, range, callSiteMarker) ->
|
||||
combinedMapping.addRangeMapping(RangeMapping(
|
||||
callSiteMarker!!.lineNumber, dest, range
|
||||
))
|
||||
|
||||
@@ -68,7 +68,8 @@ class AnonymousObjectTransformationInfo internal constructor(
|
||||
private val alreadyRegenerated: Boolean,
|
||||
val constructorDesc: String?,
|
||||
private val isStaticOrigin: Boolean,
|
||||
parentNameGenerator: NameGenerator
|
||||
parentNameGenerator: NameGenerator,
|
||||
private val capturesAnonymousObjectThatMustBeRegenerated: Boolean = false
|
||||
) : TransformationInfo {
|
||||
|
||||
override val nameGenerator by lazy {
|
||||
@@ -93,7 +94,8 @@ class AnonymousObjectTransformationInfo internal constructor(
|
||||
) : this(ownerInternalName, needReification, hashMapOf(), false, alreadyRegenerated, null, isStaticOrigin, nameGenerator)
|
||||
|
||||
override fun shouldRegenerate(sameModule: Boolean): Boolean =
|
||||
!alreadyRegenerated && (!lambdasToInline.isEmpty() || !sameModule || capturedOuterRegenerated || needReification)
|
||||
!alreadyRegenerated &&
|
||||
(!lambdasToInline.isEmpty() || !sameModule || capturedOuterRegenerated || needReification || capturesAnonymousObjectThatMustBeRegenerated)
|
||||
|
||||
override fun canRemoveAfterTransformation(): Boolean {
|
||||
// Note: It is unsafe to remove anonymous class that is referenced by GETSTATIC within lambda
|
||||
|
||||
@@ -25,7 +25,7 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
class CompareTo : IntrinsicMethod() {
|
||||
private fun genInvoke(type: Type?, v: InstructionAdapter) {
|
||||
when (type) {
|
||||
Type.INT_TYPE -> v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "compare", "(II)I", false)
|
||||
Type.INT_TYPE, Type.CHAR_TYPE -> v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "compare", "(II)I", false)
|
||||
Type.LONG_TYPE -> v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "compare", "(JJ)I", false)
|
||||
Type.FLOAT_TYPE -> v.invokestatic("java/lang/Float", "compare", "(FF)I", false)
|
||||
Type.DOUBLE_TYPE -> v.invokestatic("java/lang/Double", "compare", "(DD)I", false)
|
||||
|
||||
@@ -47,12 +47,12 @@ class Concat : IntrinsicMethod() {
|
||||
codegen.invokeAppend(element.right)
|
||||
}
|
||||
else {
|
||||
// LHS?.plus(RHS)
|
||||
receiver.put(AsmTypes.OBJECT_TYPE, v)
|
||||
// Explicit plus call LHS?.plus(RHS) or LHS.plus(RHS)
|
||||
receiver.put(AsmTypes.JAVA_STRING_TYPE, v)
|
||||
genStringBuilderConstructor(v)
|
||||
v.swap()
|
||||
genInvokeAppendMethod(v, returnType)
|
||||
codegen.invokeAppend(arguments.get(0))
|
||||
codegen.invokeAppend(arguments[0])
|
||||
}
|
||||
|
||||
v.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false)
|
||||
|
||||
@@ -28,7 +28,7 @@ internal val classId: ClassId =
|
||||
ClassId.topLevel(FqName("org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt"))
|
||||
|
||||
internal val bytecode: ByteArray by lazy {
|
||||
val stream = object {}.javaClass.classLoader.getResourceAsStream("${classId.asString()}.class")
|
||||
val stream = object {}::class.java.classLoader.getResourceAsStream("${classId.asString()}.class")
|
||||
stream.readBytes().apply {
|
||||
stream.close()
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ object JavaClassProperty : IntrinsicPropertyGetter() {
|
||||
}
|
||||
|
||||
override fun toCallable(fd: FunctionDescriptor, isSuper: Boolean, resolvedCall: ResolvedCall<*>, codegen: ExpressionCodegen): Callable {
|
||||
val classType = codegen.getState().typeMapper.mapType(resolvedCall.call.dispatchReceiver!!.type)
|
||||
val classType = codegen.state.typeMapper.mapType(resolvedCall.call.dispatchReceiver!!.type)
|
||||
return object : IntrinsicCallable(getType(Class::class.java), listOf(), classType, null) {
|
||||
override fun invokeIntrinsic(v: InstructionAdapter) {
|
||||
if (isPrimitive(classType)) {
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
class NewArray : IntrinsicMethod() {
|
||||
override fun toCallable(fd: FunctionDescriptor, isSuper: Boolean, resolvedCall: ResolvedCall<*>, codegen: ExpressionCodegen): Callable {
|
||||
val jetType = resolvedCall.resultingDescriptor.returnType!!
|
||||
val type = codegen.getState().typeMapper.mapType(jetType)
|
||||
val type = codegen.state.typeMapper.mapType(jetType)
|
||||
return object : IntrinsicCallable(type, listOf(Type.INT_TYPE), null, null) {
|
||||
override fun invokeIntrinsic(v: InstructionAdapter) {
|
||||
codegen.newArrayInstruction(jetType)
|
||||
|
||||
@@ -29,9 +29,13 @@ class DeadCodeEliminationMethodTransformer : MethodTransformer() {
|
||||
}
|
||||
|
||||
fun transformWithResult(internalClassName: String, methodNode: MethodNode): Result {
|
||||
val frames = analyze(internalClassName, methodNode, OptimizationBasicInterpreter())
|
||||
return removeDeadCodeByFrames(methodNode, frames)
|
||||
}
|
||||
|
||||
fun removeDeadCodeByFrames(methodNode: MethodNode, frames: Array<out Any?>): Result {
|
||||
val removedNodes = HashSet<AbstractInsnNode>()
|
||||
|
||||
val frames = analyze(internalClassName, methodNode, OptimizationBasicInterpreter())
|
||||
val insnList = methodNode.instructions
|
||||
val insnsArray = insnList.toArray()
|
||||
|
||||
@@ -51,6 +55,7 @@ class DeadCodeEliminationMethodTransformer : MethodTransformer() {
|
||||
}
|
||||
|
||||
class Result(val removedNodes: Set<AbstractInsnNode>) {
|
||||
fun hasRemovedAnything() = removedNodes.isNotEmpty()
|
||||
fun isRemoved(node: AbstractInsnNode) = removedNodes.contains(node)
|
||||
fun isAlive(node: AbstractInsnNode) = !isRemoved(node)
|
||||
}
|
||||
|
||||
@@ -21,8 +21,9 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.TransformationMethodVisitor;
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantBoxingMethodTransformer;
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantCoercionToUnitTransformer;
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantNullCheckMethodTransformer;
|
||||
import org.jetbrains.kotlin.codegen.optimization.captured.CapturedVarsOptimizationMethodTransformer;
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.UtilKt;
|
||||
import org.jetbrains.kotlin.codegen.optimization.nullCheck.RedundantNullCheckV2MethodTransformer;
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
|
||||
@@ -33,7 +34,9 @@ public class OptimizationMethodVisitor extends TransformationMethodVisitor {
|
||||
private static final MethodTransformer MANDATORY_METHOD_TRANSFORMER = new FixStackWithLabelNormalizationMethodTransformer();
|
||||
|
||||
private static final MethodTransformer[] OPTIMIZATION_TRANSFORMERS = new MethodTransformer[] {
|
||||
new RedundantNullCheckMethodTransformer(),
|
||||
new CapturedVarsOptimizationMethodTransformer(),
|
||||
new RedundantNullCheckV2MethodTransformer(),
|
||||
new RedundantCheckCastEliminationMethodTransformer(),
|
||||
new RedundantBoxingMethodTransformer(),
|
||||
new RedundantCoercionToUnitTransformer(),
|
||||
new DeadCodeEliminationMethodTransformer(),
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization
|
||||
|
||||
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
||||
import org.jetbrains.kotlin.codegen.optimization.nullCheck.popReferenceValueBefore
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
|
||||
class RedundantCheckCastEliminationMethodTransformer : MethodTransformer() {
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
val insns = methodNode.instructions.toArray()
|
||||
if (!insns.any { it.opcode == Opcodes.CHECKCAST }) return
|
||||
|
||||
val redundantCheckCasts = ArrayList<TypeInsnNode>()
|
||||
|
||||
val frames = analyze(internalClassName, methodNode, OptimizationBasicInterpreter())
|
||||
for (i in insns.indices) {
|
||||
val valueType = frames[i]?.top()?.type ?: continue
|
||||
val insn = insns[i]
|
||||
if (ReifiedTypeInliner.isOperationReifiedMarker(insn.previous)) continue
|
||||
|
||||
if (insn is TypeInsnNode) {
|
||||
val insnType = Type.getObjectType(insn.desc)
|
||||
if (!isTrivialSubtype(insnType, valueType)) continue
|
||||
|
||||
if (insn.opcode == Opcodes.CHECKCAST) {
|
||||
redundantCheckCasts.add(insn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
redundantCheckCasts.forEach {
|
||||
methodNode.instructions.remove(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isTrivialSubtype(superType: Type, subType: Type) =
|
||||
superType == subType
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import com.intellij.openapi.util.Pair
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.utils.toReadOnlyList
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import java.util.*
|
||||
@@ -66,7 +65,7 @@ class BoxedValueDescriptor(
|
||||
var isSafeToRemove = true; private set
|
||||
val unboxedType: Type = getUnboxedType(boxedType)
|
||||
|
||||
fun getAssociatedInsns() = associatedInsns.toReadOnlyList()
|
||||
fun getAssociatedInsns() = associatedInsns.toList()
|
||||
|
||||
fun addInsn(insnNode: AbstractInsnNode) {
|
||||
associatedInsns.add(insnNode)
|
||||
|
||||
@@ -35,14 +35,12 @@ import java.util.*
|
||||
open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasicInterpreter() {
|
||||
private val boxingPlaces = HashMap<Int, BoxedBasicValue>()
|
||||
|
||||
protected open fun createNewBoxing(insn: AbstractInsnNode, type: Type, progressionIterator: ProgressionIteratorBasicValue?): BasicValue {
|
||||
val index = insnList.indexOf(insn)
|
||||
return boxingPlaces.getOrPut(index) {
|
||||
val boxedBasicValue = CleanBoxedValue(type, insn, progressionIterator)
|
||||
onNewBoxedValue(boxedBasicValue)
|
||||
boxedBasicValue
|
||||
}
|
||||
}
|
||||
protected open fun createNewBoxing(insn: AbstractInsnNode, type: Type, progressionIterator: ProgressionIteratorBasicValue?): BasicValue =
|
||||
boxingPlaces.getOrPut(insnList.indexOf(insn)) {
|
||||
val boxedBasicValue = CleanBoxedValue(type, insn, progressionIterator)
|
||||
onNewBoxedValue(boxedBasicValue)
|
||||
boxedBasicValue
|
||||
}
|
||||
|
||||
protected fun checkUsedValue(value: BasicValue) {
|
||||
if (value is TaintedBoxedValue) {
|
||||
@@ -66,14 +64,17 @@ open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasic
|
||||
onUnboxing(insn, firstArg, value.type)
|
||||
value
|
||||
}
|
||||
insn.isIteratorMethodCallOfProgression(values) -> {
|
||||
ProgressionIteratorBasicValue(getValuesTypeOfProgressionClass(firstArg.type.internalName))
|
||||
}
|
||||
insn.isIteratorMethodCallOfProgression(values) ->
|
||||
ProgressionIteratorBasicValue.byProgressionClassType(firstArg.type)
|
||||
insn.isNextMethodCallOfProgressionIterator(values) -> {
|
||||
val progressionIterator = firstArg as? ProgressionIteratorBasicValue
|
||||
?: throw AssertionError("firstArg should be progression iterator")
|
||||
createNewBoxing(insn, AsmUtil.boxType(progressionIterator.valuesPrimitiveType), progressionIterator)
|
||||
}
|
||||
insn.isAreEqualIntrinsicForSameTypedBoxedValues(values) && canValuesBeUnboxedForAreEqual(values) -> {
|
||||
onAreEqual(insn, values[0] as BoxedBasicValue, values[1] as BoxedBasicValue)
|
||||
value
|
||||
}
|
||||
else -> {
|
||||
// N-ary operation should be a method call or multinewarray.
|
||||
// Arguments for multinewarray could be only numeric,
|
||||
@@ -100,7 +101,7 @@ open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasic
|
||||
protected open fun isExactValue(value: BasicValue) =
|
||||
value is ProgressionIteratorBasicValue ||
|
||||
value is CleanBoxedValue ||
|
||||
value.type != null && isProgressionClass(value.type.internalName)
|
||||
value.type != null && isProgressionClass(value.type)
|
||||
|
||||
override fun merge(v: BasicValue, w: BasicValue) =
|
||||
when {
|
||||
@@ -125,6 +126,7 @@ open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasic
|
||||
|
||||
protected open fun onNewBoxedValue(value: BoxedBasicValue) {}
|
||||
protected open fun onUnboxing(insn: AbstractInsnNode, value: BoxedBasicValue, resultType: Type) {}
|
||||
protected open fun onAreEqual(insn: AbstractInsnNode, value1: BoxedBasicValue, value2: BoxedBasicValue) {}
|
||||
protected open fun onMethodCallWithBoxedValue(value: BoxedBasicValue) {}
|
||||
protected open fun onMergeFail(value: BoxedBasicValue) {}
|
||||
protected open fun onMergeSuccess(v: BoxedBasicValue, w: BoxedBasicValue) {}
|
||||
@@ -190,23 +192,44 @@ private fun AbstractInsnNode.isJavaLangClassBoxing() =
|
||||
desc == JLCLASS_TO_KCLASS
|
||||
}
|
||||
|
||||
private fun AbstractInsnNode.isNextMethodCallOfProgressionIterator(values: List<BasicValue>) =
|
||||
values[0] is ProgressionIteratorBasicValue &&
|
||||
fun AbstractInsnNode.isNextMethodCallOfProgressionIterator(values: List<BasicValue>) =
|
||||
values.firstOrNull() is ProgressionIteratorBasicValue &&
|
||||
isMethodInsnWith(Opcodes.INVOKEINTERFACE) {
|
||||
name == "next"
|
||||
}
|
||||
|
||||
private fun AbstractInsnNode.isIteratorMethodCallOfProgression(values: List<BasicValue>) =
|
||||
fun AbstractInsnNode.isIteratorMethodCallOfProgression(values: List<BasicValue>) =
|
||||
isMethodInsnWith(Opcodes.INVOKEINTERFACE) {
|
||||
val firstArgType = values[0].type
|
||||
val firstArgType = values.firstOrNull()?.type
|
||||
firstArgType != null &&
|
||||
isProgressionClass(firstArgType.internalName) &&
|
||||
isProgressionClass(firstArgType) &&
|
||||
name == "iterator"
|
||||
}
|
||||
|
||||
private fun isProgressionClass(internalClassName: String) =
|
||||
RangeCodegenUtil.isRangeOrProgression(buildFqNameByInternal(internalClassName))
|
||||
fun isProgressionClass(type: Type) =
|
||||
RangeCodegenUtil.isRangeOrProgression(buildFqNameByInternal(type.internalName))
|
||||
|
||||
private fun getValuesTypeOfProgressionClass(progressionClassInternalName: String) =
|
||||
RangeCodegenUtil.getPrimitiveRangeOrProgressionElementType(buildFqNameByInternal(progressionClassInternalName))
|
||||
?.typeName?.asString() ?: error("type should be not null")
|
||||
fun AbstractInsnNode.isAreEqualIntrinsicForSameTypedBoxedValues(values: List<BasicValue>) =
|
||||
isAreEqualIntrinsic() && run {
|
||||
if (values.size != 2) return false
|
||||
|
||||
val (v1, v2) = values
|
||||
if (v1 !is BoxedBasicValue || v2 !is BoxedBasicValue) return false
|
||||
|
||||
val d1 = v1.descriptor
|
||||
val d2 = v2.descriptor
|
||||
d1.unboxedType == d2.unboxedType
|
||||
}
|
||||
|
||||
fun AbstractInsnNode.isAreEqualIntrinsic() =
|
||||
isMethodInsnWith(Opcodes.INVOKESTATIC) {
|
||||
name == "areEqual" &&
|
||||
owner == "kotlin/jvm/internal/Intrinsics" &&
|
||||
desc == "(Ljava/lang/Object;Ljava/lang/Object;)Z"
|
||||
}
|
||||
|
||||
fun canValuesBeUnboxedForAreEqual(values: List<BasicValue>): Boolean =
|
||||
!values.any {
|
||||
val unboxedType = getUnboxedType(it.type)
|
||||
unboxedType == Type.DOUBLE_TYPE || unboxedType == Type.FLOAT_TYPE
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.boxing
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnList
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
|
||||
class NullabilityInterpreter(insns: InsnList) : BoxingInterpreter(insns) {
|
||||
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue) = makeNotNullIfNeeded(insn, super.unaryOperation(insn, value))
|
||||
|
||||
override fun newOperation(insn: AbstractInsnNode) = makeNotNullIfNeeded(insn, super.newOperation(insn))
|
||||
|
||||
override fun isExactValue(value: BasicValue) = super.isExactValue(value) || value is NotNullBasicValue
|
||||
|
||||
override fun createNewBoxing(insn: AbstractInsnNode, type: Type, progressionIterator: ProgressionIteratorBasicValue?) =
|
||||
NotNullBasicValue(type)
|
||||
}
|
||||
|
||||
private fun makeNotNullIfNeeded(insn: AbstractInsnNode, value: BasicValue?): BasicValue? =
|
||||
when (insn.opcode) {
|
||||
Opcodes.ANEWARRAY, Opcodes.NEWARRAY, Opcodes.LDC, Opcodes.NEW ->
|
||||
if (value?.type?.sort == Type.OBJECT || value?.type?.sort == Type.ARRAY)
|
||||
NotNullBasicValue(value.type)
|
||||
else
|
||||
value
|
||||
|
||||
else -> value
|
||||
}
|
||||
|
||||
class NotNullBasicValue(type: Type?) : StrictBasicValue(type) {
|
||||
override fun equals(other: Any?): Boolean = other is NotNullBasicValue
|
||||
// We do not differ not-nullable values, so we should always return the same hashCode
|
||||
// Actually it doesn't really matter because analyzer is not supposed to store values in hashtables
|
||||
override fun hashCode() = 0
|
||||
}
|
||||
@@ -18,17 +18,18 @@ package org.jetbrains.kotlin.codegen.optimization.boxing;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType;
|
||||
import org.jetbrains.kotlin.codegen.RangeCodegenUtil;
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.IteratorNext;
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
public class ProgressionIteratorBasicValue extends StrictBasicValue {
|
||||
private final static ImmutableMap<String, Type> VALUES_TYPENAME_TO_TYPE;
|
||||
|
||||
static {
|
||||
ImmutableMap.Builder<String, Type> builder = ImmutableMap.builder();
|
||||
for (PrimitiveType primitiveType : RangeCodegenUtil.supportedRangeTypes()) {
|
||||
@@ -37,6 +38,15 @@ public class ProgressionIteratorBasicValue extends StrictBasicValue {
|
||||
VALUES_TYPENAME_TO_TYPE = builder.build();
|
||||
}
|
||||
|
||||
private static final ImmutableMap<PrimitiveType, ProgressionIteratorBasicValue> ITERATOR_VALUE_BY_ELEMENT_PRIMITIVE_TYPE;
|
||||
static {
|
||||
ImmutableMap.Builder<PrimitiveType, ProgressionIteratorBasicValue> builder = ImmutableMap.builder();
|
||||
for (PrimitiveType elementType : RangeCodegenUtil.supportedRangeTypes()) {
|
||||
builder.put(elementType, new ProgressionIteratorBasicValue(elementType.getTypeName().asString()));
|
||||
}
|
||||
ITERATOR_VALUE_BY_ELEMENT_PRIMITIVE_TYPE = builder.build();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Type getValuesType(@NotNull String valuesTypeName) {
|
||||
Type type = VALUES_TYPENAME_TO_TYPE.get(valuesTypeName);
|
||||
@@ -47,12 +57,20 @@ public class ProgressionIteratorBasicValue extends StrictBasicValue {
|
||||
private final Type valuesPrimitiveType;
|
||||
private final String valuesPrimitiveTypeName;
|
||||
|
||||
public ProgressionIteratorBasicValue(@NotNull String valuesPrimitiveTypeName) {
|
||||
private ProgressionIteratorBasicValue(@NotNull String valuesPrimitiveTypeName) {
|
||||
super(IteratorNext.Companion.getPrimitiveIteratorType(Name.identifier(valuesPrimitiveTypeName)));
|
||||
this.valuesPrimitiveType = getValuesType(valuesPrimitiveTypeName);
|
||||
this.valuesPrimitiveTypeName = valuesPrimitiveTypeName;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public static ProgressionIteratorBasicValue byProgressionClassType(@NotNull Type progressionClassType) {
|
||||
FqName classFqName = new FqName(progressionClassType.getClassName());
|
||||
PrimitiveType elementType = RangeCodegenUtil.getPrimitiveRangeOrProgressionElementType(classFqName);
|
||||
return ITERATOR_VALUE_BY_ELEMENT_PRIMITIVE_TYPE.get(elementType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Type getValuesPrimitiveType() {
|
||||
return valuesPrimitiveType;
|
||||
|
||||
@@ -84,6 +84,13 @@ internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterprete
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAreEqual(insn: AbstractInsnNode, value1: BoxedBasicValue, value2: BoxedBasicValue) {
|
||||
val descriptor1 = value1.descriptor
|
||||
val descriptor2 = value2.descriptor
|
||||
candidatesBoxedValues.merge(descriptor1, descriptor2)
|
||||
descriptor1.addInsn(insn)
|
||||
}
|
||||
|
||||
override fun onMethodCallWithBoxedValue(value: BoxedBasicValue) {
|
||||
markValueAsDirty(value)
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ import kotlin.collections.CollectionsKt;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue;
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.UtilKt;
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
@@ -48,7 +50,7 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
|
||||
adaptLocalVariableTableForBoxedValues(node, frames);
|
||||
|
||||
applyVariablesRemapping(node, buildVariablesRemapping(valuesToOptimize, node));
|
||||
UtilKt.remapLocalVariables(node, buildVariablesRemapping(valuesToOptimize, node));
|
||||
|
||||
adaptInstructionsForBoxedValues(node, valuesToOptimize);
|
||||
}
|
||||
@@ -221,21 +223,6 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
return remapping;
|
||||
}
|
||||
|
||||
private static void applyVariablesRemapping(@NotNull MethodNode node, @NotNull int[] remapping) {
|
||||
for (AbstractInsnNode insn : node.instructions.toArray()) {
|
||||
if (insn instanceof VarInsnNode) {
|
||||
((VarInsnNode) insn).var = remapping[((VarInsnNode) insn).var];
|
||||
}
|
||||
if (insn instanceof IincInsnNode) {
|
||||
((IincInsnNode) insn).var = remapping[((IincInsnNode) insn).var];
|
||||
}
|
||||
}
|
||||
|
||||
for (LocalVariableNode localVariableNode : node.localVariables) {
|
||||
localVariableNode.index = remapping[localVariableNode.index];
|
||||
}
|
||||
}
|
||||
|
||||
private static void adaptInstructionsForBoxedValues(
|
||||
@NotNull MethodNode node,
|
||||
@NotNull RedundantBoxedValuesCollection values
|
||||
@@ -341,9 +328,68 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
);
|
||||
node.instructions.set(insn, new InsnNode(Opcodes.ICONST_1));
|
||||
break;
|
||||
case Opcodes.INVOKESTATIC:
|
||||
if (BoxingInterpreterKt.isAreEqualIntrinsic(insn)) {
|
||||
adaptAreEqualIntrinsic(node, insn, value);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
// fall-through to default
|
||||
}
|
||||
default:
|
||||
// CHECKCAST or unboxing-method call
|
||||
node.instructions.remove(insn);
|
||||
}
|
||||
}
|
||||
|
||||
private static void adaptAreEqualIntrinsic(@NotNull MethodNode node, @NotNull AbstractInsnNode insn, @NotNull BoxedValueDescriptor value) {
|
||||
Type unboxedType = value.getUnboxedType();
|
||||
|
||||
switch (unboxedType.getSort()) {
|
||||
case Type.BOOLEAN:
|
||||
case Type.BYTE:
|
||||
case Type.SHORT:
|
||||
case Type.INT:
|
||||
case Type.CHAR:
|
||||
adaptAreEqualIntrinsicForInt(node, insn);
|
||||
break;
|
||||
case Type.LONG:
|
||||
adaptAreEqualIntrinsicForLong(node, insn);
|
||||
break;
|
||||
case Type.OBJECT:
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Unexpected unboxed type kind: " + unboxedType);
|
||||
}
|
||||
}
|
||||
|
||||
private static void adaptAreEqualIntrinsicForInt(@NotNull MethodNode node, @NotNull AbstractInsnNode insn) {
|
||||
LabelNode lNotEqual = new LabelNode(new Label());
|
||||
LabelNode lDone = new LabelNode(new Label());
|
||||
node.instructions.insertBefore(insn, new JumpInsnNode(Opcodes.IF_ICMPNE, lNotEqual));
|
||||
node.instructions.insertBefore(insn, new InsnNode(Opcodes.ICONST_1));
|
||||
node.instructions.insertBefore(insn, new JumpInsnNode(Opcodes.GOTO, lDone));
|
||||
node.instructions.insertBefore(insn, lNotEqual);
|
||||
node.instructions.insertBefore(insn, new InsnNode(Opcodes.ICONST_0));
|
||||
node.instructions.insertBefore(insn, lDone);
|
||||
|
||||
node.instructions.remove(insn);
|
||||
}
|
||||
|
||||
private static void adaptAreEqualIntrinsicForLong(@NotNull MethodNode node, @NotNull AbstractInsnNode insn) {
|
||||
node.instructions.insertBefore(insn, new InsnNode(Opcodes.LCMP));
|
||||
ifEqual1Else0(node, insn);
|
||||
node.instructions.remove(insn);
|
||||
}
|
||||
|
||||
private static void ifEqual1Else0(@NotNull MethodNode node, @NotNull AbstractInsnNode insn) {
|
||||
LabelNode lNotEqual = new LabelNode(new Label());
|
||||
LabelNode lDone = new LabelNode(new Label());
|
||||
node.instructions.insertBefore(insn, new JumpInsnNode(Opcodes.IFNE, lNotEqual));
|
||||
node.instructions.insertBefore(insn, new InsnNode(Opcodes.ICONST_1));
|
||||
node.instructions.insertBefore(insn, new JumpInsnNode(Opcodes.GOTO, lDone));
|
||||
node.instructions.insertBefore(insn, lNotEqual);
|
||||
node.instructions.insertBefore(insn, new InsnNode(Opcodes.ICONST_0));
|
||||
node.instructions.insertBefore(insn, lDone);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ class RedundantCoercionToUnitTransformer : MethodTransformer() {
|
||||
private val frames by lazy { analyzeMethodBody() }
|
||||
|
||||
fun transform() {
|
||||
if (!insns.any { it.isUnitOrNull() }) return
|
||||
if (!insns.any { it.isUnitInstanceOrNull() }) return
|
||||
|
||||
computeTransformations()
|
||||
for ((insn, transformation) in transformations.entries) {
|
||||
@@ -158,7 +158,7 @@ class RedundantCoercionToUnitTransformer : MethodTransformer() {
|
||||
transformations[insn] = replaceWithPopTransformation(boxedValueSize)
|
||||
}
|
||||
|
||||
insn.isUnitOrNull() -> {
|
||||
insn.isUnitInstanceOrNull() -> {
|
||||
transformations[insn] = replaceWithNopTransformation()
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ class RedundantCoercionToUnitTransformer : MethodTransformer() {
|
||||
it.isPrimitiveBoxing() && (it as MethodInsnNode).owner == resultType
|
||||
|
||||
private fun isTransformablePopOperand(insn: AbstractInsnNode) =
|
||||
insn.opcode == Opcodes.CHECKCAST || insn.isPrimitiveBoxing() || insn.isUnitOrNull()
|
||||
insn.opcode == Opcodes.CHECKCAST || insn.isPrimitiveBoxing() || insn.isUnitInstanceOrNull()
|
||||
|
||||
private fun isDontTouch(insn: AbstractInsnNode) =
|
||||
dontTouchInsnIndices[insnList.indexOf(insn)]
|
||||
@@ -240,6 +240,9 @@ class RedundantCoercionToUnitTransformer : MethodTransformer() {
|
||||
|
||||
}
|
||||
|
||||
fun AbstractInsnNode.isUnitOrNull() =
|
||||
opcode == Opcodes.ACONST_NULL ||
|
||||
opcode == Opcodes.GETSTATIC && this is FieldInsnNode && owner == "kotlin/Unit" && name == "INSTANCE"
|
||||
fun AbstractInsnNode.isUnitInstanceOrNull() =
|
||||
opcode == Opcodes.ACONST_NULL || isUnitInstance()
|
||||
|
||||
fun AbstractInsnNode.isUnitInstance() =
|
||||
opcode == Opcodes.GETSTATIC &&
|
||||
this is FieldInsnNode && owner == "kotlin/Unit" && name == "INSTANCE"
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.boxing;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
import org.jetbrains.org.objectweb.asm.tree.*;
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue;
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class RedundantNullCheckMethodTransformer extends MethodTransformer {
|
||||
|
||||
@Override
|
||||
public void transform(@NotNull String internalClassName, @NotNull MethodNode methodNode) {
|
||||
while (removeRedundantNullCheckPass(internalClassName, methodNode)) {
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean removeRedundantNullCheckPass(@NotNull String internalClassName, @NotNull MethodNode methodNode) {
|
||||
InsnList insnList = methodNode.instructions;
|
||||
Frame<BasicValue>[] frames = analyze(
|
||||
internalClassName, methodNode,
|
||||
new NullabilityInterpreter(insnList)
|
||||
);
|
||||
|
||||
List<AbstractInsnNode> insnsToOptimize = new ArrayList<AbstractInsnNode>();
|
||||
|
||||
for (int i = 0; i < insnList.size(); i++) {
|
||||
Frame<BasicValue> frame = frames[i];
|
||||
AbstractInsnNode insn = insnList.get(i);
|
||||
|
||||
if ((insn.getOpcode() == Opcodes.IFNULL || insn.getOpcode() == Opcodes.IFNONNULL) &&
|
||||
frame != null && frame.getStack(frame.getStackSize() - 1) instanceof NotNullBasicValue) {
|
||||
insnsToOptimize.add(insn);
|
||||
}
|
||||
}
|
||||
|
||||
for (AbstractInsnNode insn : insnsToOptimize) {
|
||||
if (insn.getPrevious() != null && insn.getPrevious().getOpcode() == Opcodes.DUP) {
|
||||
insnList.remove(insn.getPrevious());
|
||||
}
|
||||
else {
|
||||
insnList.insertBefore(insn, new InsnNode(Opcodes.POP));
|
||||
}
|
||||
|
||||
assert insn.getOpcode() == Opcodes.IFNULL
|
||||
|| insn.getOpcode() == Opcodes.IFNONNULL : "only IFNULL/IFNONNULL are supported";
|
||||
|
||||
if (insn.getOpcode() == Opcodes.IFNULL) {
|
||||
insnList.remove(insn);
|
||||
}
|
||||
else {
|
||||
insnList.set(
|
||||
insn,
|
||||
new JumpInsnNode(Opcodes.GOTO, ((JumpInsnNode) insn).label)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return insnsToOptimize.size() > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.captured
|
||||
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.removeEmptyCatchBlocks
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.removeUnusedLocalVariables
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
|
||||
class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
Transformer(internalClassName, methodNode).run()
|
||||
}
|
||||
|
||||
// Tracks proper usages of objects corresponding to captured variables.
|
||||
//
|
||||
// The 'kotlin.jvm.internal.Ref.*' instance can be replaced with a local variable,
|
||||
// if all of the following conditions are satisfied:
|
||||
// * It is created inside a current method.
|
||||
// * The only permitted operations on it are:
|
||||
// - store to a local variable
|
||||
// - ALOAD, ASTORE
|
||||
// - DUP, POP
|
||||
// - GETFIELD <owner>.element, PUTFIELD <owner>.element
|
||||
// * There's a corresponding local variable definition,
|
||||
// and all ALOAD/ASTORE instructions operate on that particular local variable.
|
||||
// * Its 'element' field is initialized at start of local variable visibility range.
|
||||
//
|
||||
// Note that for code that doesn't create Ref objects explicitly these conditions are true,
|
||||
// unless the Ref object escapes to a local class constructor (including local classes for lambdas).
|
||||
//
|
||||
private class CapturedVarDescriptor(val newInsn: TypeInsnNode, val refType: Type, val valueType: Type) : ReferenceValueDescriptor {
|
||||
var hazard = false
|
||||
|
||||
var initCallInsn: MethodInsnNode? = null
|
||||
var localVar: LocalVariableNode? = null
|
||||
var localVarIndex = -1
|
||||
val astoreInsns: MutableCollection<VarInsnNode> = LinkedHashSet()
|
||||
val aloadInsns: MutableCollection<VarInsnNode> = LinkedHashSet()
|
||||
val stackInsns: MutableCollection<AbstractInsnNode> = LinkedHashSet()
|
||||
val getFieldInsns: MutableCollection<FieldInsnNode> = LinkedHashSet()
|
||||
val putFieldInsns: MutableCollection<FieldInsnNode> = LinkedHashSet()
|
||||
|
||||
fun canRewrite(): Boolean =
|
||||
!hazard &&
|
||||
initCallInsn != null &&
|
||||
localVar != null &&
|
||||
localVarIndex >= 0
|
||||
|
||||
override fun onUseAsTainted() {
|
||||
hazard = true
|
||||
}
|
||||
}
|
||||
|
||||
private class Transformer(private val internalClassName: String, private val methodNode: MethodNode) {
|
||||
private val refValues = ArrayList<CapturedVarDescriptor>()
|
||||
private val refValuesByNewInsn = LinkedHashMap<TypeInsnNode, CapturedVarDescriptor>()
|
||||
private val insns = methodNode.instructions.toArray()
|
||||
private lateinit var frames: Array<out Frame<BasicValue>?>
|
||||
|
||||
val hasRewritableRefValues: Boolean
|
||||
get() = refValues.isNotEmpty()
|
||||
|
||||
fun run() {
|
||||
createRefValues()
|
||||
if (!hasRewritableRefValues) return
|
||||
|
||||
analyze()
|
||||
if (!hasRewritableRefValues) return
|
||||
|
||||
rewrite()
|
||||
}
|
||||
|
||||
private fun AbstractInsnNode.getIndex() = methodNode.instructions.indexOf(this)
|
||||
|
||||
private fun createRefValues() {
|
||||
for (insn in insns) {
|
||||
if (insn.opcode == Opcodes.NEW && insn is TypeInsnNode) {
|
||||
val type = Type.getObjectType(insn.desc)
|
||||
if (AsmTypes.isSharedVarType(type)) {
|
||||
val valueType = REF_TYPE_TO_ELEMENT_TYPE[type.internalName] ?: continue
|
||||
val refValue = CapturedVarDescriptor(insn, type, valueType)
|
||||
refValues.add(refValue)
|
||||
refValuesByNewInsn[insn] = refValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class Interpreter : ReferenceTrackingInterpreter() {
|
||||
override fun newOperation(insn: AbstractInsnNode): BasicValue =
|
||||
refValuesByNewInsn[insn]?.let { descriptor ->
|
||||
ProperTrackedReferenceValue(descriptor.refType, descriptor)
|
||||
}
|
||||
?: super.newOperation(insn)
|
||||
|
||||
override fun processRefValueUsage(value: TrackedReferenceValue, insn: AbstractInsnNode, position: Int) {
|
||||
for (descriptor in value.descriptors) {
|
||||
if (descriptor !is CapturedVarDescriptor) throw AssertionError("Unexpected descriptor: $descriptor")
|
||||
when {
|
||||
insn.opcode == Opcodes.ALOAD ->
|
||||
descriptor.aloadInsns.add(insn as VarInsnNode)
|
||||
insn.opcode == Opcodes.ASTORE ->
|
||||
descriptor.astoreInsns.add(insn as VarInsnNode)
|
||||
insn.opcode == Opcodes.GETFIELD && insn is FieldInsnNode && insn.name == REF_ELEMENT_FIELD && position == 0 ->
|
||||
descriptor.getFieldInsns.add(insn)
|
||||
insn.opcode == Opcodes.PUTFIELD && insn is FieldInsnNode && insn.name == REF_ELEMENT_FIELD && position == 0 ->
|
||||
descriptor.putFieldInsns.add(insn)
|
||||
insn.opcode == Opcodes.INVOKESPECIAL && insn is MethodInsnNode && insn.name == INIT_METHOD_NAME && position == 0 ->
|
||||
if (descriptor.initCallInsn != null && descriptor.initCallInsn != insn)
|
||||
descriptor.hazard = true
|
||||
else
|
||||
descriptor.initCallInsn = insn
|
||||
insn.opcode == Opcodes.DUP ->
|
||||
descriptor.stackInsns.add(insn)
|
||||
else ->
|
||||
descriptor.hazard = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun analyze() {
|
||||
frames = MethodTransformer.analyze(internalClassName, methodNode, Interpreter())
|
||||
trackPops()
|
||||
assignLocalVars()
|
||||
|
||||
refValues.removeAll { !it.canRewrite() }
|
||||
}
|
||||
|
||||
private fun trackPops() {
|
||||
for (i in insns.indices) {
|
||||
val frame = frames[i] ?: continue
|
||||
val insn = insns[i]
|
||||
|
||||
when (insn.opcode) {
|
||||
Opcodes.POP -> {
|
||||
frame.top()?.getCapturedVarOrNull()?.run { stackInsns.add(insn) }
|
||||
}
|
||||
Opcodes.POP2 -> {
|
||||
val top = frame.top()
|
||||
if (top?.size == 1) {
|
||||
top.getCapturedVarOrNull()?.hazard = true
|
||||
frame.peek(1)?.getCapturedVarOrNull()?.hazard = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun BasicValue.getCapturedVarOrNull() =
|
||||
safeAs<ProperTrackedReferenceValue>()?.descriptor?.safeAs<CapturedVarDescriptor>()
|
||||
|
||||
private fun assignLocalVars() {
|
||||
for (localVar in methodNode.localVariables) {
|
||||
val type = Type.getType(localVar.desc)
|
||||
if (!AsmTypes.isSharedVarType(type)) continue
|
||||
|
||||
val startFrame = frames[localVar.start.getIndex()] ?: continue
|
||||
|
||||
val refValue = startFrame.getLocal(localVar.index) as? ProperTrackedReferenceValue ?: continue
|
||||
val descriptor = refValue.descriptor as? CapturedVarDescriptor ?: continue
|
||||
|
||||
if (descriptor.hazard) continue
|
||||
|
||||
if (descriptor.localVar == null) {
|
||||
descriptor.localVar = localVar
|
||||
}
|
||||
else {
|
||||
descriptor.hazard = true
|
||||
}
|
||||
}
|
||||
|
||||
for (refValue in refValues) {
|
||||
if (refValue.hazard) continue
|
||||
val localVar = refValue.localVar ?: continue
|
||||
|
||||
if (refValue.valueType.size != 1) {
|
||||
refValue.localVarIndex = methodNode.maxLocals
|
||||
methodNode.maxLocals += 2
|
||||
localVar.index = refValue.localVarIndex
|
||||
}
|
||||
else {
|
||||
refValue.localVarIndex = localVar.index
|
||||
}
|
||||
|
||||
val startIndex = localVar.start.getIndex()
|
||||
val initFieldInsns = refValue.putFieldInsns.filter { it.getIndex() < startIndex }
|
||||
if (initFieldInsns.size != 1) {
|
||||
refValue.hazard = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun rewrite() {
|
||||
for (refValue in refValues) {
|
||||
if (!refValue.canRewrite()) continue
|
||||
|
||||
rewriteRefValue(refValue)
|
||||
}
|
||||
|
||||
methodNode.removeEmptyCatchBlocks()
|
||||
methodNode.removeUnusedLocalVariables()
|
||||
}
|
||||
|
||||
private fun rewriteRefValue(capturedVar: CapturedVarDescriptor) {
|
||||
methodNode.instructions.run {
|
||||
capturedVar.localVar!!.let {
|
||||
it.signature = null
|
||||
it.desc = capturedVar.valueType.descriptor
|
||||
}
|
||||
|
||||
remove(capturedVar.newInsn)
|
||||
remove(capturedVar.initCallInsn!!)
|
||||
capturedVar.stackInsns.forEach { remove(it) }
|
||||
capturedVar.aloadInsns.forEach { remove(it) }
|
||||
capturedVar.astoreInsns.forEach { remove(it) }
|
||||
|
||||
capturedVar.getFieldInsns.forEach {
|
||||
set(it, VarInsnNode(capturedVar.valueType.getOpcode(Opcodes.ILOAD), capturedVar.localVarIndex))
|
||||
}
|
||||
|
||||
capturedVar.putFieldInsns.forEach {
|
||||
set(it, VarInsnNode(capturedVar.valueType.getOpcode(Opcodes.ISTORE), capturedVar.localVarIndex))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal const val REF_ELEMENT_FIELD = "element"
|
||||
internal const val INIT_METHOD_NAME = "<init>"
|
||||
|
||||
internal val REF_TYPE_TO_ELEMENT_TYPE = HashMap<String, Type>().apply {
|
||||
put(AsmTypes.OBJECT_REF_TYPE.internalName, AsmTypes.OBJECT_TYPE)
|
||||
PrimitiveType.values().forEach {
|
||||
put(AsmTypes.sharedTypeForPrimitive(it).internalName, AsmTypes.valueTypeForPrimitive(it))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.captured
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
|
||||
abstract class ReferenceTrackingInterpreter : OptimizationBasicInterpreter() {
|
||||
override fun merge(v: BasicValue, w: BasicValue): BasicValue =
|
||||
when {
|
||||
v is ProperTrackedReferenceValue && w is ProperTrackedReferenceValue ->
|
||||
if (v.descriptor == w.descriptor)
|
||||
v
|
||||
else
|
||||
TaintedTrackedReferenceValue(
|
||||
getTaintedValueType(v.type, w.type),
|
||||
setOf(v.descriptor, w.descriptor)
|
||||
)
|
||||
|
||||
v is TrackedReferenceValue || w is TrackedReferenceValue ->
|
||||
TaintedTrackedReferenceValue(
|
||||
getTaintedValueType(v.type, w.type),
|
||||
v.referenceValueDescriptors + w.referenceValueDescriptors
|
||||
)
|
||||
|
||||
else ->
|
||||
super.merge(v, w)
|
||||
}
|
||||
|
||||
private val BasicValue.referenceValueDescriptors: Set<ReferenceValueDescriptor>
|
||||
get() = if (this is TrackedReferenceValue) this.descriptors else emptySet()
|
||||
|
||||
private fun getTaintedValueType(type1: Type?, type2: Type?): Type =
|
||||
when {
|
||||
type1 == null || type2 == null -> AsmTypes.OBJECT_TYPE
|
||||
type1 == type2 -> type1
|
||||
else -> AsmTypes.OBJECT_TYPE
|
||||
}
|
||||
|
||||
override fun copyOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue? =
|
||||
if (value is TrackedReferenceValue) {
|
||||
checkRefValuesUsages(insn, listOf(value))
|
||||
value
|
||||
}
|
||||
else {
|
||||
super.copyOperation(insn, value)
|
||||
}
|
||||
|
||||
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue? {
|
||||
checkRefValuesUsages(insn, listOf(value))
|
||||
return super.unaryOperation(insn, value)
|
||||
}
|
||||
|
||||
override fun binaryOperation(insn: AbstractInsnNode, value1: BasicValue, value2: BasicValue): BasicValue? {
|
||||
checkRefValuesUsages(insn, listOf(value1, value2))
|
||||
return super.binaryOperation(insn, value1, value2)
|
||||
}
|
||||
|
||||
override fun ternaryOperation(insn: AbstractInsnNode, value1: BasicValue, value2: BasicValue, value3: BasicValue): BasicValue? {
|
||||
checkRefValuesUsages(insn, listOf(value1, value2, value3))
|
||||
return super.ternaryOperation(insn, value1, value2, value3)
|
||||
}
|
||||
|
||||
override fun naryOperation(insn: AbstractInsnNode, values: List<BasicValue>): BasicValue? {
|
||||
checkRefValuesUsages(insn, values)
|
||||
return super.naryOperation(insn, values)
|
||||
}
|
||||
|
||||
protected open fun checkRefValuesUsages(insn: AbstractInsnNode, values: List<BasicValue>) {
|
||||
values.forEach { value ->
|
||||
if (value is TaintedTrackedReferenceValue) {
|
||||
value.descriptors.forEach { it.onUseAsTainted() }
|
||||
}
|
||||
}
|
||||
|
||||
values.forEachIndexed { pos, value ->
|
||||
if (value is TrackedReferenceValue) {
|
||||
processRefValueUsage(value, insn, pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun processRefValueUsage(value: TrackedReferenceValue, insn: AbstractInsnNode, position: Int)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.captured
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
|
||||
interface ReferenceValueDescriptor {
|
||||
fun onUseAsTainted()
|
||||
}
|
||||
|
||||
abstract class TrackedReferenceValue(type: Type): StrictBasicValue(type) {
|
||||
abstract val descriptors: Set<ReferenceValueDescriptor>
|
||||
}
|
||||
|
||||
class ProperTrackedReferenceValue(type: Type, val descriptor: ReferenceValueDescriptor) : TrackedReferenceValue(type) {
|
||||
override val descriptors: Set<ReferenceValueDescriptor>
|
||||
get() = setOf(descriptor)
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other === this ||
|
||||
other is ProperTrackedReferenceValue && other.descriptor == this.descriptor
|
||||
|
||||
override fun hashCode(): Int =
|
||||
descriptor.hashCode()
|
||||
|
||||
override fun toString(): String =
|
||||
"[$descriptor]"
|
||||
}
|
||||
|
||||
class TaintedTrackedReferenceValue(type: Type, override val descriptors: Set<ReferenceValueDescriptor>) : TrackedReferenceValue(type) {
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other === this ||
|
||||
other is TaintedTrackedReferenceValue && other.descriptors == this.descriptors
|
||||
|
||||
override fun hashCode(): Int =
|
||||
descriptors.hashCode()
|
||||
|
||||
override fun toString(): String =
|
||||
"!$descriptors"
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen.optimization.common;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil;
|
||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
|
||||
import org.jetbrains.org.objectweb.asm.Handle;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
@@ -136,7 +137,7 @@ public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implem
|
||||
case NEW:
|
||||
return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
|
||||
default:
|
||||
throw new Error("Internal error.");
|
||||
throw new IllegalArgumentException("Unexpected instruction: " + InlineCodegenUtil.getInsnOpcodeText(insn));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +222,7 @@ public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implem
|
||||
case PUTFIELD:
|
||||
return null;
|
||||
default:
|
||||
throw new Error("Internal error.");
|
||||
throw new IllegalArgumentException("Unexpected instruction: " + InlineCodegenUtil.getInsnOpcodeText(insn));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,7 +341,7 @@ public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implem
|
||||
case IFNONNULL:
|
||||
return null;
|
||||
default:
|
||||
throw new Error("Internal error.");
|
||||
throw new IllegalArgumentException("Unexpected instruction: " + InlineCodegenUtil.getInsnOpcodeText(insn));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ open class StrictBasicValue(type: Type?) : BasicValue(type) {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other?.javaClass != javaClass) return false
|
||||
if (other == null || other::class.java != this::class.java) return false
|
||||
if (!super.equals(other)) return false
|
||||
|
||||
other as StrictBasicValue
|
||||
|
||||
@@ -17,8 +17,10 @@
|
||||
package org.jetbrains.kotlin.codegen.optimization.common
|
||||
|
||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
|
||||
val AbstractInsnNode.isMeaningful: Boolean get() =
|
||||
@@ -50,9 +52,7 @@ fun MethodNode.prepareForEmitting() {
|
||||
|
||||
// local variables with live ranges starting after last meaningful instruction lead to VerifyError
|
||||
localVariables = localVariables.filter { lv ->
|
||||
InsnSequence(lv.start, lv.end).any { insn ->
|
||||
insn.isMeaningful
|
||||
}
|
||||
InsnSequence(lv.start, lv.end).any(AbstractInsnNode::isMeaningful)
|
||||
}
|
||||
|
||||
// We should remove linenumbers after last meaningful instruction
|
||||
@@ -71,10 +71,64 @@ fun MethodNode.prepareForEmitting() {
|
||||
|
||||
fun MethodNode.removeEmptyCatchBlocks() {
|
||||
tryCatchBlocks = tryCatchBlocks.filter { tcb ->
|
||||
InsnSequence(tcb.start, tcb.end).any { insn ->
|
||||
insn.isMeaningful
|
||||
InsnSequence(tcb.start, tcb.end).any(AbstractInsnNode::isMeaningful)
|
||||
}
|
||||
}
|
||||
|
||||
fun MethodNode.removeUnusedLocalVariables() {
|
||||
val used = BooleanArray(maxLocals) { false }
|
||||
for (insn in instructions) {
|
||||
when (insn) {
|
||||
is VarInsnNode -> {
|
||||
val varIndex = insn.`var`
|
||||
used[varIndex] = true
|
||||
if (insn.isSize2LoadStoreOperation()) {
|
||||
used[varIndex + 1] = true
|
||||
}
|
||||
}
|
||||
is IincInsnNode ->
|
||||
used[insn.`var`] = true
|
||||
}
|
||||
}
|
||||
for (localVar in localVariables) {
|
||||
val varIndex = localVar.index
|
||||
used[varIndex] = true
|
||||
val type = Type.getType(localVar.desc)
|
||||
if (type.size == 2) {
|
||||
used[varIndex + 1] = true
|
||||
}
|
||||
}
|
||||
|
||||
if (used.all { it }) return
|
||||
|
||||
val remapping = IntArray(maxLocals) { 0 }
|
||||
var lastUnused = 0
|
||||
for (i in remapping.indices) {
|
||||
remapping[i] = lastUnused
|
||||
if (used[i]) {
|
||||
lastUnused++
|
||||
}
|
||||
}
|
||||
|
||||
remapLocalVariables(remapping)
|
||||
}
|
||||
|
||||
private fun VarInsnNode.isSize2LoadStoreOperation() =
|
||||
opcode == LLOAD || opcode == DLOAD || opcode == LSTORE || opcode == DSTORE
|
||||
|
||||
fun MethodNode.remapLocalVariables(remapping: IntArray) {
|
||||
for (insn in instructions.toArray()) {
|
||||
when (insn) {
|
||||
is VarInsnNode ->
|
||||
insn.`var` = remapping[insn.`var`]
|
||||
is IincInsnNode ->
|
||||
insn.`var` = remapping[insn.`var`]
|
||||
}
|
||||
}
|
||||
|
||||
for (localVariableNode in localVariables) {
|
||||
localVariableNode.index = remapping[localVariableNode.index]
|
||||
}
|
||||
}
|
||||
|
||||
inline fun AbstractInsnNode.findNextOrNull(predicate: (AbstractInsnNode) -> Boolean): AbstractInsnNode? {
|
||||
@@ -119,9 +173,16 @@ val AbstractInsnNode.intConstant: Int? get() =
|
||||
|
||||
fun insnListOf(vararg insns: AbstractInsnNode) = InsnList().apply { insns.forEach { add(it) } }
|
||||
|
||||
fun AbstractInsnNode.isStoreOperation(): Boolean = getOpcode() in Opcodes.ISTORE..Opcodes.ASTORE
|
||||
fun AbstractInsnNode.isLoadOperation(): Boolean = getOpcode() in Opcodes.ILOAD..Opcodes.ALOAD
|
||||
fun AbstractInsnNode.isStoreOperation(): Boolean = opcode in Opcodes.ISTORE..Opcodes.ASTORE
|
||||
fun AbstractInsnNode.isLoadOperation(): Boolean = opcode in Opcodes.ILOAD..Opcodes.ALOAD
|
||||
|
||||
val AbstractInsnNode?.insnText get() = InlineCodegenUtil.getInsnText(this)
|
||||
val AbstractInsnNode?.debugText get() =
|
||||
if (this == null) "<null>" else "${this.javaClass.simpleName}: $insnText"
|
||||
if (this == null) "<null>" else "${this::class.java.simpleName}: $insnText"
|
||||
|
||||
internal inline fun <reified T : AbstractInsnNode> AbstractInsnNode.isInsn(opcode: Int, condition: T.() -> Boolean): Boolean =
|
||||
takeInsnIf(opcode, condition) != null
|
||||
|
||||
internal inline fun <reified T : AbstractInsnNode> AbstractInsnNode.takeInsnIf(opcode: Int, condition: T.() -> Boolean): T? =
|
||||
takeIf { it.opcode == opcode }?.safeAs<T>()?.takeIf { it.condition() }
|
||||
|
||||
|
||||
@@ -58,16 +58,9 @@ internal class FixStackAnalyzer(
|
||||
for (marker in context.fakeAlwaysFalseIfeqMarkers) {
|
||||
val next = marker.next
|
||||
if (next is JumpInsnNode) {
|
||||
val nop = InsnNode(Opcodes.NOP)
|
||||
expectedStackNode[next.label] = nop
|
||||
method.instructions.insert(next, nop)
|
||||
method.instructions.remove(marker)
|
||||
method.instructions.remove(next)
|
||||
context.nodesToRemoveOnCleanup.add(nop)
|
||||
expectedStackNode[next.label] = marker
|
||||
}
|
||||
}
|
||||
|
||||
context.fakeAlwaysFalseIfeqMarkers.clear()
|
||||
}
|
||||
|
||||
private val analyzer = InternalAnalyzer(owner, method, context)
|
||||
|
||||
@@ -39,8 +39,6 @@ internal class FixStackContext(val methodNode: MethodNode) {
|
||||
val openingInlineMethodMarker = hashMapOf<AbstractInsnNode, AbstractInsnNode>()
|
||||
var consistentInlineMarkers: Boolean = true; private set
|
||||
|
||||
val nodesToRemoveOnCleanup = arrayListOf<AbstractInsnNode>()
|
||||
|
||||
init {
|
||||
saveStackMarkerForRestoreMarker = insertTryCatchBlocksMarkers(methodNode)
|
||||
isThereAnyTryCatch = saveStackMarkerForRestoreMarker.isNotEmpty()
|
||||
|
||||
@@ -39,31 +39,51 @@ class FixStackMethodTransformer : MethodTransformer() {
|
||||
}
|
||||
|
||||
if (context.isAnalysisRequired()) {
|
||||
val analyzer = FixStackAnalyzer(internalClassName, methodNode, context)
|
||||
analyzer.analyze()
|
||||
|
||||
methodNode.maxStack = methodNode.maxStack + analyzer.maxExtraStackSize
|
||||
|
||||
val actions = arrayListOf<() -> Unit>()
|
||||
|
||||
transformBreakContinueGotos(methodNode, context, actions, analyzer)
|
||||
|
||||
transformSaveRestoreStackMarkers(methodNode, context, actions, analyzer)
|
||||
|
||||
actions.forEach { it() }
|
||||
analyzeAndTransformBreakContinueGotos(context, internalClassName, methodNode)
|
||||
removeAlwaysFalseIfeqMarkers(context, methodNode)
|
||||
analyzeAndTransformSaveRestoreStack(context, internalClassName, methodNode)
|
||||
}
|
||||
|
||||
context.fakeAlwaysTrueIfeqMarkers.forEach { marker ->
|
||||
replaceAlwaysTrueIfeqWithGoto(methodNode, marker)
|
||||
}
|
||||
removeAlwaysTrueIfeqMarkers(context, methodNode)
|
||||
removeAlwaysFalseIfeqMarkers(context, methodNode)
|
||||
}
|
||||
|
||||
private fun analyzeAndTransformBreakContinueGotos(context: FixStackContext, internalClassName: String, methodNode: MethodNode) {
|
||||
val analyzer = FixStackAnalyzer(internalClassName, methodNode, context)
|
||||
analyzer.analyze()
|
||||
|
||||
methodNode.maxStack = methodNode.maxStack + analyzer.maxExtraStackSize
|
||||
|
||||
val actions = arrayListOf<() -> Unit>()
|
||||
|
||||
transformBreakContinueGotos(methodNode, context, actions, analyzer)
|
||||
|
||||
actions.forEach { it() }
|
||||
}
|
||||
|
||||
private fun analyzeAndTransformSaveRestoreStack(context: FixStackContext, internalClassName: String, methodNode: MethodNode) {
|
||||
val analyzer = FixStackAnalyzer(internalClassName, methodNode, context)
|
||||
analyzer.analyze()
|
||||
|
||||
val actions = arrayListOf<() -> Unit>()
|
||||
|
||||
transformSaveRestoreStackMarkers(methodNode, context, actions, analyzer)
|
||||
|
||||
actions.forEach { it() }
|
||||
}
|
||||
|
||||
private fun removeAlwaysFalseIfeqMarkers(context: FixStackContext, methodNode: MethodNode) {
|
||||
context.fakeAlwaysFalseIfeqMarkers.forEach { marker ->
|
||||
removeAlwaysFalseIfeq(methodNode, marker)
|
||||
}
|
||||
context.fakeAlwaysFalseIfeqMarkers.clear()
|
||||
}
|
||||
|
||||
context.nodesToRemoveOnCleanup.forEach {
|
||||
methodNode.instructions.remove(it)
|
||||
private fun removeAlwaysTrueIfeqMarkers(context: FixStackContext, methodNode: MethodNode) {
|
||||
context.fakeAlwaysTrueIfeqMarkers.forEach { marker ->
|
||||
replaceAlwaysTrueIfeqWithGoto(methodNode, marker)
|
||||
}
|
||||
context.fakeAlwaysTrueIfeqMarkers.clear()
|
||||
}
|
||||
|
||||
private fun transformBreakContinueGotos(
|
||||
|
||||
@@ -26,7 +26,7 @@ fun <V : Value> Frame<V>.top(): V? =
|
||||
peek(0)
|
||||
|
||||
fun <V : Value> Frame<V>.peek(offset: Int): V? =
|
||||
if (stackSize >= offset) getStack(stackSize - offset - 1) else null
|
||||
if (stackSize > offset) getStack(stackSize - offset - 1) else null
|
||||
|
||||
class SavedStackDescriptor(
|
||||
val savedValues: List<BasicValue>,
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.nullCheck
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.*
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.TypeInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
|
||||
class NullabilityInterpreter : OptimizationBasicInterpreter() {
|
||||
override fun newOperation(insn: AbstractInsnNode): BasicValue? {
|
||||
val defaultResult = super.newOperation(insn)
|
||||
val resultType = defaultResult?.type
|
||||
|
||||
return when {
|
||||
insn.opcode == Opcodes.ACONST_NULL ->
|
||||
NullBasicValue
|
||||
insn.opcode == Opcodes.NEW ->
|
||||
NotNullBasicValue(resultType)
|
||||
insn.opcode == Opcodes.LDC && resultType.isReferenceType() ->
|
||||
NotNullBasicValue(resultType)
|
||||
insn.isUnitInstance() ->
|
||||
NotNullBasicValue(resultType)
|
||||
else ->
|
||||
defaultResult
|
||||
}
|
||||
}
|
||||
|
||||
private fun Type?.isReferenceType() =
|
||||
this?.sort.let { it == Type.OBJECT || it == Type.ARRAY }
|
||||
|
||||
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? {
|
||||
val defaultResult = super.unaryOperation(insn, value)
|
||||
val resultType = defaultResult?.type
|
||||
|
||||
return when {
|
||||
insn.opcode == Opcodes.CHECKCAST ->
|
||||
value
|
||||
insn.opcode == Opcodes.NEWARRAY || insn.opcode == Opcodes.ANEWARRAY ->
|
||||
NotNullBasicValue(resultType)
|
||||
else ->
|
||||
defaultResult
|
||||
}
|
||||
}
|
||||
|
||||
override fun naryOperation(insn: AbstractInsnNode, values: List<BasicValue>): BasicValue? {
|
||||
val defaultResult = super.naryOperation(insn, values)
|
||||
val resultType = defaultResult?.type
|
||||
|
||||
return when {
|
||||
insn.isBoxing() ->
|
||||
NotNullBasicValue(resultType)
|
||||
insn.isIteratorMethodCallOfProgression(values) ->
|
||||
ProgressionIteratorBasicValue.byProgressionClassType(values[0].type)
|
||||
insn.isNextMethodCallOfProgressionIterator(values) ->
|
||||
NotNullBasicValue(resultType)
|
||||
else ->
|
||||
defaultResult
|
||||
}
|
||||
}
|
||||
|
||||
override fun merge(v: BasicValue, w: BasicValue): BasicValue =
|
||||
when {
|
||||
v is NullBasicValue && w is NullBasicValue ->
|
||||
NullBasicValue
|
||||
v is NullBasicValue || w is NullBasicValue ->
|
||||
StrictBasicValue.REFERENCE_VALUE
|
||||
v is ProgressionIteratorBasicValue && w is ProgressionIteratorBasicValue ->
|
||||
mergeNotNullValuesOfSameKind(v, w)
|
||||
v is ProgressionIteratorBasicValue && w is NotNullBasicValue ->
|
||||
NotNullBasicValue.NOT_NULL_REFERENCE_VALUE
|
||||
w is ProgressionIteratorBasicValue && v is NotNullBasicValue ->
|
||||
NotNullBasicValue.NOT_NULL_REFERENCE_VALUE
|
||||
v is NotNullBasicValue && w is NotNullBasicValue ->
|
||||
mergeNotNullValuesOfSameKind(v, w)
|
||||
else ->
|
||||
super.merge(v, w)
|
||||
}
|
||||
|
||||
private fun mergeNotNullValuesOfSameKind(v: StrictBasicValue, w: StrictBasicValue) =
|
||||
if (v.type == w.type) v else NotNullBasicValue.NOT_NULL_REFERENCE_VALUE
|
||||
|
||||
}
|
||||
|
||||
|
||||
fun TypeInsnNode.getObjectType(): Type =
|
||||
Type.getObjectType(desc)
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.nullCheck
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.DeadCodeEliminationMethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.ProgressionIteratorBasicValue
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
|
||||
class RedundantNullCheckMethodTransformer : MethodTransformer() {
|
||||
private val deadCodeElimination = DeadCodeEliminationMethodTransformer()
|
||||
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
while (runSingleNullCheckEliminationPass(internalClassName, methodNode)) {
|
||||
deadCodeElimination.transform(internalClassName, methodNode)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isAlwaysFalse(opcode: Int, nullability: Nullability) =
|
||||
(opcode == Opcodes.IFNULL && nullability == Nullability.NOT_NULL) ||
|
||||
(opcode == Opcodes.IFNONNULL && nullability == Nullability.NULL)
|
||||
|
||||
private fun isAlwaysTrue(opcode: Int, nullability: Nullability) =
|
||||
(opcode == Opcodes.IFNULL && nullability == Nullability.NULL) ||
|
||||
(opcode == Opcodes.IFNONNULL && nullability == Nullability.NOT_NULL)
|
||||
|
||||
|
||||
private fun runSingleNullCheckEliminationPass(internalClassName: String, methodNode: MethodNode): Boolean {
|
||||
val insnList = methodNode.instructions
|
||||
val instructions = insnList.toArray()
|
||||
|
||||
val nullCheckIfs = instructions.mapNotNullTo(SmartList<JumpInsnNode>()) {
|
||||
it.safeAs<JumpInsnNode>()?.takeIf {
|
||||
it.opcode == Opcodes.IFNULL ||
|
||||
it.opcode == Opcodes.IFNONNULL
|
||||
}
|
||||
}
|
||||
if (nullCheckIfs.isEmpty()) return false
|
||||
|
||||
val frames = analyze(internalClassName, methodNode, NullabilityInterpreter())
|
||||
|
||||
val redundantNullCheckIfs = nullCheckIfs.mapNotNull { insn ->
|
||||
frames[instructions.indexOf(insn)]?.top()?.let { top ->
|
||||
val nullability = top.getNullability()
|
||||
if (nullability == Nullability.NULLABLE)
|
||||
null
|
||||
else
|
||||
Pair(insn, nullability)
|
||||
}
|
||||
}
|
||||
if (redundantNullCheckIfs.isEmpty()) return false
|
||||
|
||||
for ((insn, nullability) in redundantNullCheckIfs) {
|
||||
val previous = insn.previous
|
||||
when (previous?.opcode) {
|
||||
Opcodes.ALOAD, Opcodes.DUP ->
|
||||
insnList.remove(previous)
|
||||
else ->
|
||||
insnList.insert(previous, InsnNode(Opcodes.POP))
|
||||
}
|
||||
|
||||
when {
|
||||
isAlwaysTrue(insn.opcode, nullability) ->
|
||||
insnList.set(insn, JumpInsnNode(Opcodes.GOTO, insn.label))
|
||||
isAlwaysFalse(insn.opcode, nullability) ->
|
||||
insnList.remove(insn)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.nullCheck
|
||||
|
||||
import org.jetbrains.kotlin.codegen.coroutines.withInstructionAdapter
|
||||
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
|
||||
import org.jetbrains.kotlin.codegen.optimization.DeadCodeEliminationMethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.isInsn
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.assertedCast
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
|
||||
class RedundantNullCheckV2MethodTransformer : MethodTransformer() {
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
while (TransformerPass(internalClassName, methodNode).run()) {}
|
||||
}
|
||||
|
||||
private class TransformerPass(val internalClassName: String, val methodNode: MethodNode) {
|
||||
private var changes = false
|
||||
|
||||
private fun AbstractInsnNode.getIndex() =
|
||||
methodNode.instructions.indexOf(this)
|
||||
|
||||
fun run(): Boolean {
|
||||
val checkedReferenceTypes = analyzeTypesAndRemoveDeadCode()
|
||||
eliminateRedundantChecks(checkedReferenceTypes)
|
||||
|
||||
return changes
|
||||
}
|
||||
|
||||
private fun analyzeTypesAndRemoveDeadCode(): Map<AbstractInsnNode, Type> {
|
||||
val insns = methodNode.instructions.toArray()
|
||||
val frames = analyze(internalClassName, methodNode, OptimizationBasicInterpreter())
|
||||
|
||||
val checkedReferenceTypes = HashMap<AbstractInsnNode, Type>()
|
||||
for (i in insns.indices) {
|
||||
val insn = insns[i]
|
||||
val frame = frames[i]
|
||||
if (insn.isInstanceOfOrNullCheck()) {
|
||||
checkedReferenceTypes[insn] = frame?.top()?.type ?: continue
|
||||
}
|
||||
else if (insn.isCheckParameterNotNull()) {
|
||||
checkedReferenceTypes[insn] = frame?.peek(1)?.type ?: continue
|
||||
}
|
||||
}
|
||||
|
||||
val dceResult = DeadCodeEliminationMethodTransformer().removeDeadCodeByFrames(methodNode, frames)
|
||||
if (dceResult.hasRemovedAnything()) {
|
||||
changes = true
|
||||
}
|
||||
|
||||
return checkedReferenceTypes
|
||||
}
|
||||
|
||||
private fun eliminateRedundantChecks(checkedReferenceTypes: Map<AbstractInsnNode, Type>) {
|
||||
val nullabilityAssumptions = injectNullabilityAssumptions(checkedReferenceTypes)
|
||||
|
||||
val nullabilityMap = analyzeNullabilities()
|
||||
|
||||
nullabilityAssumptions.revert()
|
||||
|
||||
transformTrivialChecks(nullabilityMap)
|
||||
}
|
||||
|
||||
private fun injectNullabilityAssumptions(checkedReferenceTypes: Map<AbstractInsnNode, Type>) =
|
||||
NullabilityAssumptionsBuilder(checkedReferenceTypes).injectNullabilityAssumptions()
|
||||
|
||||
private fun analyzeNullabilities(): Map<AbstractInsnNode, Nullability> {
|
||||
val frames = analyze(internalClassName, methodNode, NullabilityInterpreter())
|
||||
val insns = methodNode.instructions.toArray()
|
||||
val nullabilityMap = HashMap<AbstractInsnNode, Nullability>()
|
||||
for (i in insns.indices) {
|
||||
val nullability = frames[i]?.top()?.getNullability() ?: continue
|
||||
if (nullability == Nullability.NULLABLE) continue
|
||||
|
||||
val insn = insns[i]
|
||||
if (insn.isInstanceOfOrNullCheck()) {
|
||||
nullabilityMap[insn] = nullability
|
||||
}
|
||||
}
|
||||
return nullabilityMap
|
||||
}
|
||||
|
||||
private fun transformTrivialChecks(nullabilityMap: Map<AbstractInsnNode, Nullability>) {
|
||||
for ((insn, nullability) in nullabilityMap) {
|
||||
when (insn.opcode) {
|
||||
Opcodes.IFNULL -> transformTrivialNullJump(insn as JumpInsnNode, nullability == Nullability.NULL)
|
||||
Opcodes.IFNONNULL -> transformTrivialNullJump(insn as JumpInsnNode, nullability == Nullability.NOT_NULL)
|
||||
Opcodes.INSTANCEOF -> transformInstanceOf(insn, nullability)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformTrivialNullJump(insn: JumpInsnNode, alwaysTrue: Boolean) {
|
||||
changes = true
|
||||
|
||||
methodNode.instructions.run {
|
||||
popReferenceValueBefore(insn)
|
||||
if (alwaysTrue) {
|
||||
set(insn, JumpInsnNode(Opcodes.GOTO, insn.label))
|
||||
}
|
||||
else {
|
||||
remove(insn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformInstanceOf(insn: AbstractInsnNode, nullability: Nullability) {
|
||||
if (nullability != Nullability.NULL) return
|
||||
if (ReifiedTypeInliner.isOperationReifiedMarker(insn.previous)) return
|
||||
|
||||
changes = true
|
||||
|
||||
val nextOpcode = insn.next?.opcode
|
||||
if (nextOpcode == Opcodes.IFEQ || nextOpcode == Opcodes.IFNE)
|
||||
transformNullInstanceOfWithJump(insn)
|
||||
else
|
||||
transformNullInstanceOf(insn)
|
||||
}
|
||||
|
||||
private fun transformNullInstanceOf(insn: AbstractInsnNode) {
|
||||
methodNode.instructions.run {
|
||||
popReferenceValueBefore(insn)
|
||||
set(insn, InsnNode(Opcodes.ICONST_0))
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformNullInstanceOfWithJump(insn: AbstractInsnNode) {
|
||||
methodNode.instructions.run {
|
||||
popReferenceValueBefore(insn)
|
||||
val jump = insn.next.assertedCast<JumpInsnNode> { "JumpInsnNode expected" }
|
||||
remove(insn)
|
||||
if (jump.opcode == Opcodes.IFEQ) {
|
||||
set(jump, JumpInsnNode(Opcodes.GOTO, jump.label))
|
||||
}
|
||||
else {
|
||||
remove(jump)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class NullabilityAssumptionsBuilder(val checkedReferenceTypes: Map<AbstractInsnNode, Type>) {
|
||||
|
||||
private val checksDependingOnVariable = HashMap<Int, MutableList<AbstractInsnNode>>()
|
||||
|
||||
fun injectNullabilityAssumptions(): NullabilityAssumptions {
|
||||
collectVariableDependentChecks()
|
||||
return injectAssumptions()
|
||||
}
|
||||
|
||||
private fun collectVariableDependentChecks() {
|
||||
for (insn in methodNode.instructions) {
|
||||
if (insn.isInstanceOfOrNullCheck()) {
|
||||
val previous = insn.previous ?: continue
|
||||
if (previous.opcode == Opcodes.ALOAD) {
|
||||
addDependentCheck(insn, previous as VarInsnNode)
|
||||
}
|
||||
else if (previous.opcode == Opcodes.DUP) {
|
||||
val previous2 = previous.previous ?: continue
|
||||
if (previous2.opcode == Opcodes.ALOAD) {
|
||||
addDependentCheck(insn, previous2 as VarInsnNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (insn.isCheckParameterNotNull()) {
|
||||
val ldcInsn = insn.previous ?: continue
|
||||
if (ldcInsn.opcode != Opcodes.LDC) continue
|
||||
val aLoadInsn = ldcInsn.previous ?: continue
|
||||
if (aLoadInsn.opcode != Opcodes.ALOAD) continue
|
||||
addDependentCheck(insn, aLoadInsn as VarInsnNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addDependentCheck(insn: AbstractInsnNode, aLoadInsn: VarInsnNode) {
|
||||
checksDependingOnVariable.getOrPut(aLoadInsn.`var`) {
|
||||
SmartList<AbstractInsnNode>()
|
||||
}.add(insn)
|
||||
}
|
||||
|
||||
private fun injectAssumptions(): NullabilityAssumptions {
|
||||
val nullabilityAssumptions = NullabilityAssumptions()
|
||||
for ((varIndex, dependentChecks) in checksDependingOnVariable) {
|
||||
for (checkInsn in dependentChecks) {
|
||||
val varType = checkedReferenceTypes[checkInsn]
|
||||
?: throw AssertionError("No var type @${checkInsn.getIndex()}")
|
||||
nullabilityAssumptions.injectAssumptionsForCheck(varIndex, checkInsn, varType)
|
||||
}
|
||||
}
|
||||
return nullabilityAssumptions
|
||||
}
|
||||
|
||||
private fun NullabilityAssumptions.injectAssumptionsForCheck(varIndex: Int, insn: AbstractInsnNode, varType: Type) {
|
||||
when (insn.opcode) {
|
||||
Opcodes.IFNULL,
|
||||
Opcodes.IFNONNULL ->
|
||||
injectAssumptionsForNullCheck(varIndex, insn as JumpInsnNode, varType)
|
||||
Opcodes.INVOKESTATIC -> {
|
||||
assert(insn.isCheckParameterNotNull()) { "Expected non-null parameter check @${insn.getIndex()}"}
|
||||
injectAssumptionsForParameterNotNullCheck(varIndex, insn, varType)
|
||||
}
|
||||
Opcodes.INSTANCEOF ->
|
||||
injectAssumptionsForInstanceOfCheck(varIndex, insn, varType)
|
||||
}
|
||||
}
|
||||
|
||||
private fun NullabilityAssumptions.injectAssumptionsForNullCheck(varIndex: Int, insn: JumpInsnNode, varType: Type) {
|
||||
// ALOAD v
|
||||
// IFNULL L
|
||||
// <...> -- v is not null here
|
||||
// L:
|
||||
// <...> -- v is null here
|
||||
|
||||
val jumpsIfNull = insn.opcode == Opcodes.IFNULL
|
||||
val originalLabel = insn.label
|
||||
originalLabels[insn] = originalLabel
|
||||
insn.label = synthetic(LabelNode(Label()))
|
||||
|
||||
val insertAfterNull = if (jumpsIfNull) insn.label else insn
|
||||
val insertAfterNonNull = if (jumpsIfNull) insn else insn.label
|
||||
|
||||
methodNode.instructions.run {
|
||||
add(insn.label)
|
||||
|
||||
insert(insertAfterNull, listOfSynthetics {
|
||||
aconst(null)
|
||||
store(varIndex, varType)
|
||||
if (jumpsIfNull) {
|
||||
goTo(originalLabel.label)
|
||||
}
|
||||
})
|
||||
|
||||
insert(insertAfterNonNull, listOfSynthetics {
|
||||
anew(varType)
|
||||
store(varIndex, varType)
|
||||
if (!jumpsIfNull) {
|
||||
goTo(originalLabel.label)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun NullabilityAssumptions.injectAssumptionsForParameterNotNullCheck(varIndex: Int, insn: AbstractInsnNode, varType: Type) {
|
||||
// ALOAD v
|
||||
// LDC param_name
|
||||
// INVOKESTATIC checkParameterIsNotNull
|
||||
// <...> -- v is not null here (otherwise an exception was thrown)
|
||||
|
||||
methodNode.instructions.insert(insn, listOfSynthetics {
|
||||
anew(varType)
|
||||
store(varIndex, varType)
|
||||
})
|
||||
}
|
||||
|
||||
private fun NullabilityAssumptions.injectAssumptionsForInstanceOfCheck(varIndex: Int, insn: AbstractInsnNode, varType: Type) {
|
||||
// ALOAD v
|
||||
// INSTANCEOF T
|
||||
// IFEQ L
|
||||
// <...> -- v is not null here (because it is an instance of T)
|
||||
// L:
|
||||
// <...> -- v is something else here (maybe null)
|
||||
|
||||
val next = insn.next ?: return
|
||||
if (next.opcode != Opcodes.IFEQ && next.opcode != Opcodes.IFNE) return
|
||||
if (next !is JumpInsnNode) return
|
||||
val jumpsIfInstance = next.opcode == Opcodes.IFNE
|
||||
|
||||
val originalLabel: LabelNode?
|
||||
val insertAfterNotNull: AbstractInsnNode
|
||||
if (jumpsIfInstance) {
|
||||
originalLabel = next.label
|
||||
originalLabels[next] = next.label
|
||||
val newLabel = synthetic(LabelNode(Label()))
|
||||
methodNode.instructions.add(newLabel)
|
||||
next.label = newLabel
|
||||
insertAfterNotNull = newLabel
|
||||
}
|
||||
else {
|
||||
originalLabel = null
|
||||
insertAfterNotNull = next
|
||||
}
|
||||
|
||||
methodNode.instructions.run {
|
||||
insert(insertAfterNotNull, listOfSynthetics {
|
||||
anew(varType)
|
||||
store(varIndex, varType)
|
||||
if (originalLabel != null) {
|
||||
goTo(originalLabel.label)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inner class NullabilityAssumptions {
|
||||
val originalLabels = HashMap<JumpInsnNode, LabelNode>()
|
||||
val syntheticInstructions = ArrayList<AbstractInsnNode>()
|
||||
|
||||
fun <T : AbstractInsnNode> synthetic(insn: T): T {
|
||||
syntheticInstructions.add(insn)
|
||||
return insn
|
||||
}
|
||||
|
||||
inline fun listOfSynthetics(block: InstructionAdapter.() -> Unit): InsnList {
|
||||
val insnList = withInstructionAdapter(block)
|
||||
for (insn in insnList) {
|
||||
synthetic(insn)
|
||||
}
|
||||
return insnList
|
||||
}
|
||||
|
||||
fun revert() {
|
||||
methodNode.instructions.run {
|
||||
syntheticInstructions.forEach { remove(it) }
|
||||
}
|
||||
for ((jumpInsn, originalLabel) in originalLabels) {
|
||||
jumpInsn.label = originalLabel
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun AbstractInsnNode.isInstanceOfOrNullCheck() =
|
||||
opcode == Opcodes.INSTANCEOF || opcode == Opcodes.IFNULL || opcode == Opcodes.IFNONNULL
|
||||
|
||||
internal fun AbstractInsnNode.isCheckParameterNotNull() =
|
||||
isInsn<MethodInsnNode>(Opcodes.INVOKESTATIC) {
|
||||
owner == "kotlin/jvm/internal/Intrinsics" &&
|
||||
name == "checkParameterIsNotNull" &&
|
||||
desc == "(Ljava/lang/Object;Ljava/lang/String;)V"
|
||||
}
|
||||
|
||||
internal fun InsnList.popReferenceValueBefore(insn: AbstractInsnNode) {
|
||||
val prev = insn.previous
|
||||
when (prev?.opcode) {
|
||||
Opcodes.ACONST_NULL,
|
||||
Opcodes.DUP,
|
||||
Opcodes.ALOAD ->
|
||||
remove(prev)
|
||||
else ->
|
||||
insertBefore(insn, InsnNode(Opcodes.POP))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.nullCheck
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.ProgressionIteratorBasicValue
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
|
||||
class NotNullBasicValue(type: Type?) : StrictBasicValue(type) {
|
||||
override fun equals(other: Any?): Boolean = other is NotNullBasicValue
|
||||
// We do not differ not-nullable values, so we should always return the same hashCode
|
||||
// Actually it doesn't really matter because analyzer is not supposed to store values in hashtables
|
||||
override fun hashCode() = 0
|
||||
|
||||
companion object {
|
||||
val NOT_NULL_REFERENCE_VALUE = NotNullBasicValue(StrictBasicValue.REFERENCE_VALUE.type)
|
||||
}
|
||||
}
|
||||
|
||||
object NullBasicValue : StrictBasicValue(AsmTypes.OBJECT_TYPE)
|
||||
|
||||
enum class Nullability {
|
||||
NULL, NOT_NULL, NULLABLE;
|
||||
fun isNull() = this == NULL
|
||||
fun isNotNull() = this == NOT_NULL
|
||||
}
|
||||
|
||||
fun BasicValue.getNullability(): Nullability =
|
||||
when (this) {
|
||||
is NullBasicValue -> Nullability.NULL
|
||||
is NotNullBasicValue -> Nullability.NOT_NULL
|
||||
is ProgressionIteratorBasicValue -> Nullability.NOT_NULL
|
||||
else -> Nullability.NULLABLE
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user