mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-18 08:31:29 +00:00
Compare commits
457 Commits
abannykh/v
...
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 |
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">
|
||||
|
||||
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" />
|
||||
|
||||
37
ChangeLog.md
37
ChangeLog.md
@@ -3,6 +3,42 @@
|
||||
<!-- 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
|
||||
@@ -12,6 +48,7 @@
|
||||
|
||||
### 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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
72
build.xml
72
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>
|
||||
@@ -764,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>
|
||||
@@ -784,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">
|
||||
@@ -876,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"/>
|
||||
|
||||
@@ -1013,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"/>
|
||||
@@ -1032,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}"/>
|
||||
@@ -1338,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()
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -54,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
|
||||
@@ -135,7 +135,7 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
|
||||
(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.mapSignature(functionDescriptor, contextKind, remainingParameters, false)
|
||||
val signature = typeMapper.mapSignatureWithCustomParameters(functionDescriptor, contextKind, remainingParameters, false)
|
||||
val mv = classBuilder.newMethod(OtherOrigin(methodElement, functionDescriptor), flags,
|
||||
signature.asmMethod.name,
|
||||
signature.asmMethod.descriptor,
|
||||
@@ -251,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
|
||||
|
||||
@@ -265,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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -4320,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();
|
||||
|
||||
@@ -920,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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -57,7 +57,6 @@ import java.util.List;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.getDeprecatedAccessFlag;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.getVisibilityForBackingField;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.isPropertyWithBackingFieldCopyInOuterClass;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConstOrHasJvmFieldAnnotation;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
|
||||
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.FIELD_FOR_PROPERTY;
|
||||
@@ -189,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())) {
|
||||
@@ -199,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
|
||||
) {
|
||||
|
||||
@@ -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 {
|
||||
@@ -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 }) {
|
||||
|
||||
@@ -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
|
||||
@@ -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 ?: ""))
|
||||
|
||||
@@ -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);
|
||||
@@ -271,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();
|
||||
@@ -312,7 +311,7 @@ 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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -92,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];
|
||||
@@ -103,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) {
|
||||
@@ -151,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
|
||||
) {
|
||||
@@ -179,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
|
||||
@@ -405,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
|
||||
|
||||
@@ -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()));
|
||||
@@ -486,6 +487,11 @@ public class MethodInliner {
|
||||
);
|
||||
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;
|
||||
|
||||
@@ -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
|
||||
))
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.load.java.lazy.types.RawTypeImpl;
|
||||
import org.jetbrains.kotlin.load.kotlin.JavaFlexibleTypeDeserializer;
|
||||
import org.jetbrains.kotlin.load.kotlin.TypeSignatureMappingKt;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.serialization.AnnotationSerializer;
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf;
|
||||
import org.jetbrains.kotlin.serialization.SerializerExtension;
|
||||
@@ -77,7 +78,7 @@ public class JvmSerializerExtension extends SerializerExtension {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializePackage(@NotNull ProtoBuf.Package.Builder proto) {
|
||||
public void serializePackage(@NotNull FqName packageFqName, @NotNull ProtoBuf.Package.Builder proto) {
|
||||
if (!moduleName.equals(JvmAbi.DEFAULT_MODULE_NAME)) {
|
||||
proto.setExtension(JvmProtoBuf.packageModuleName, stringTable.getStringIndex(moduleName));
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class JvmStringTable(private val typeMapper: KotlinTypeMapper) : StringTable {
|
||||
|
||||
val lastRecord = records.lastOrNull()
|
||||
if (lastRecord != null && lastRecord.isTrivial()) {
|
||||
lastRecord.setRange(lastRecord.range + 1)
|
||||
lastRecord.range = lastRecord.range + 1
|
||||
}
|
||||
else records.add(Record.newBuilder())
|
||||
}
|
||||
@@ -93,12 +93,12 @@ class JvmStringTable(private val typeMapper: KotlinTypeMapper) : StringTable {
|
||||
else {
|
||||
val predefinedIndex = JvmNameResolver.getPredefinedStringIndex(string)
|
||||
if (predefinedIndex != null) {
|
||||
record.setPredefinedIndex(predefinedIndex)
|
||||
record.predefinedIndex = predefinedIndex
|
||||
// TODO: move all records with predefined names to the end and do not write associated strings for them (since they are ignored)
|
||||
strings.add("")
|
||||
}
|
||||
else {
|
||||
record.setOperation(Record.Operation.DESC_TO_CLASS_ID)
|
||||
record.operation = Record.Operation.DESC_TO_CLASS_ID
|
||||
strings.add("L${string.replace('.', '$')};")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import java.io.File
|
||||
|
||||
class GenerationState @JvmOverloads constructor(
|
||||
@@ -70,8 +69,9 @@ class GenerationState @JvmOverloads constructor(
|
||||
abstract class GenerateClassFilter {
|
||||
abstract fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject): Boolean
|
||||
abstract fun shouldGenerateClass(processingClassOrObject: KtClassOrObject): Boolean
|
||||
abstract fun shouldGeneratePackagePart(jetFile: KtFile): Boolean
|
||||
abstract fun shouldGeneratePackagePart(ktFile: KtFile): Boolean
|
||||
abstract fun shouldGenerateScript(script: KtScript): Boolean
|
||||
open fun shouldGenerateClassMembers(processingClassOrObject: KtClassOrObject) = shouldGenerateClass(processingClassOrObject)
|
||||
|
||||
companion object {
|
||||
@JvmField val GENERATE_ALL: GenerateClassFilter = object : GenerateClassFilter() {
|
||||
@@ -81,7 +81,7 @@ class GenerationState @JvmOverloads constructor(
|
||||
|
||||
override fun shouldGenerateScript(script: KtScript): Boolean = true
|
||||
|
||||
override fun shouldGeneratePackagePart(jetFile: KtFile): Boolean = true
|
||||
override fun shouldGeneratePackagePart(ktFile: KtFile): Boolean = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,7 +92,8 @@ class GenerationState @JvmOverloads constructor(
|
||||
val incrementalCacheForThisTarget: IncrementalCache?
|
||||
val packagesWithObsoleteParts: Set<FqName>
|
||||
val obsoleteMultifileClasses: List<FqName>
|
||||
val deserializationConfiguration: DeserializationConfiguration = CompilerDeserializationConfiguration(configuration)
|
||||
val deserializationConfiguration: DeserializationConfiguration =
|
||||
CompilerDeserializationConfiguration(configuration.languageVersionSettings)
|
||||
|
||||
init {
|
||||
val icComponents = configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS)
|
||||
@@ -113,7 +114,7 @@ class GenerationState @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
val extraJvmDiagnosticsTrace: BindingTrace = DelegatingBindingTrace(bindingContext, "For extra diagnostics in ${this.javaClass}", false)
|
||||
val extraJvmDiagnosticsTrace: BindingTrace = DelegatingBindingTrace(bindingContext, "For extra diagnostics in ${this::class.java}", false)
|
||||
private val interceptedBuilderFactory: ClassBuilderFactory
|
||||
private var used = false
|
||||
|
||||
@@ -123,7 +124,8 @@ class GenerationState @JvmOverloads constructor(
|
||||
extraJvmDiagnosticsTrace.bindingContext.diagnostics
|
||||
}
|
||||
|
||||
val isJvm8Target: Boolean = configuration.get(JVMConfigurationKeys.JVM_TARGET) == JvmTarget.JVM_1_8
|
||||
val target = configuration.get(JVMConfigurationKeys.JVM_TARGET) ?: JvmTarget.DEFAULT
|
||||
val isJvm8Target: Boolean = target == JvmTarget.JVM_1_8
|
||||
val isJvm8TargetWithDefaults: Boolean = isJvm8Target && configuration.getBoolean(JVMConfigurationKeys.JVM8_TARGET_WITH_DEFAULTS)
|
||||
val generateDefaultImplsForJvm8: Boolean = configuration.getBoolean(JVMConfigurationKeys.INTERFACE_COMPATIBILITY)
|
||||
|
||||
@@ -162,7 +164,7 @@ class GenerationState @JvmOverloads constructor(
|
||||
|
||||
val rootContext: CodegenContext<*> = RootContext(this)
|
||||
|
||||
val classFileVersion: Int = if (isJvm8Target) Opcodes.V1_8 else Opcodes.V1_6
|
||||
val classFileVersion: Int = target.bytecodeVersion
|
||||
|
||||
val generateParametersMetadata: Boolean = configuration.getBoolean(JVMConfigurationKeys.PARAMETERS_METADATA)
|
||||
|
||||
|
||||
@@ -192,6 +192,10 @@ public class KotlinTypeMapper {
|
||||
return asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor);
|
||||
}
|
||||
|
||||
if (descriptor instanceof ConstructorDescriptor) {
|
||||
return mapClass(((ConstructorDescriptor) descriptor).getConstructedClass());
|
||||
}
|
||||
|
||||
DeclarationDescriptor container = descriptor.getContainingDeclaration();
|
||||
if (container instanceof PackageFragmentDescriptor) {
|
||||
String packageMemberOwner = internalNameForPackageMemberOwner((CallableMemberDescriptor) descriptor, publicFacade);
|
||||
@@ -702,15 +706,14 @@ public class KotlinTypeMapper {
|
||||
|
||||
@NotNull
|
||||
public CallableMethod mapToCallableMethod(@NotNull FunctionDescriptor descriptor, boolean superCall) {
|
||||
if (descriptor instanceof TypeAliasConstructorDescriptor) {
|
||||
return mapToCallableMethod(((TypeAliasConstructorDescriptor) descriptor).getUnderlyingConstructorDescriptor(), superCall);
|
||||
}
|
||||
|
||||
if (descriptor instanceof ClassConstructorDescriptor) {
|
||||
JvmMethodSignature method = mapSignatureSkipGeneric(descriptor);
|
||||
Type owner = mapClass(((ClassConstructorDescriptor) descriptor).getContainingDeclaration());
|
||||
String defaultImplDesc = mapDefaultMethod(descriptor, OwnerKind.IMPLEMENTATION).getDescriptor();
|
||||
return new CallableMethod(owner, owner, defaultImplDesc, method, INVOKESPECIAL, null, null, null, false);
|
||||
if (descriptor instanceof ConstructorDescriptor) {
|
||||
JvmMethodSignature method = mapSignatureSkipGeneric(descriptor.getOriginal());
|
||||
Type owner = mapOwner(descriptor);
|
||||
String defaultImplDesc = mapDefaultMethod(descriptor.getOriginal(), OwnerKind.IMPLEMENTATION).getDescriptor();
|
||||
return new CallableMethod(
|
||||
owner, owner, defaultImplDesc, method, INVOKESPECIAL,
|
||||
null, null, null, false
|
||||
);
|
||||
}
|
||||
|
||||
if (descriptor instanceof LocalVariableAccessorDescriptor) {
|
||||
@@ -958,7 +961,7 @@ public class KotlinTypeMapper {
|
||||
|
||||
if (!(descriptor instanceof ConstructorDescriptor) &&
|
||||
descriptor.getVisibility() == Visibilities.INTERNAL &&
|
||||
!descriptor.getAnnotations().hasAnnotation(KotlinBuiltIns.FQ_NAMES.publishedApi)) {
|
||||
!DescriptorUtilsKt.isPublishedApi(descriptor)) {
|
||||
return name + "$" + NameUtils.sanitizeAsJavaIdentifier(moduleName);
|
||||
}
|
||||
|
||||
@@ -1027,31 +1030,28 @@ public class KotlinTypeMapper {
|
||||
}
|
||||
}
|
||||
|
||||
if (f instanceof TypeAliasConstructorDescriptor) {
|
||||
return mapSignature(((TypeAliasConstructorDescriptor) f).getUnderlyingConstructorDescriptor(), kind, skipGenericSignature);
|
||||
}
|
||||
|
||||
if (f instanceof FunctionImportedFromObject) {
|
||||
return mapSignature(((FunctionImportedFromObject) f).getCallableFromObject(), kind, skipGenericSignature);
|
||||
}
|
||||
|
||||
if (CoroutineCodegenUtilKt.isSuspendFunctionNotSuspensionView(f)) {
|
||||
return mapSignature(CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(f), kind, skipGenericSignature);
|
||||
}
|
||||
|
||||
if (f instanceof ConstructorDescriptor) {
|
||||
return mapSignature(f, kind, f.getOriginal().getValueParameters(), skipGenericSignature);
|
||||
}
|
||||
|
||||
return mapSignature(f, kind, f.getValueParameters(), skipGenericSignature);
|
||||
return mapSignatureWithCustomParameters(f, kind, f.getValueParameters(), skipGenericSignature);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JvmMethodGenericSignature mapSignature(
|
||||
public JvmMethodGenericSignature mapSignatureWithCustomParameters(
|
||||
@NotNull FunctionDescriptor f,
|
||||
@NotNull OwnerKind kind,
|
||||
@NotNull List<ValueParameterDescriptor> valueParameters,
|
||||
boolean skipGenericSignature
|
||||
) {
|
||||
if (f instanceof FunctionImportedFromObject) {
|
||||
return mapSignature(((FunctionImportedFromObject) f).getCallableFromObject(), kind, skipGenericSignature);
|
||||
}
|
||||
else if (f instanceof TypeAliasConstructorDescriptor) {
|
||||
return mapSignature(((TypeAliasConstructorDescriptor) f).getUnderlyingConstructorDescriptor(), kind, valueParameters, skipGenericSignature);
|
||||
}
|
||||
|
||||
checkOwnerCompatibility(f);
|
||||
|
||||
JvmSignatureWriter sw = skipGenericSignature || f instanceof AccessorForCallableDescriptor
|
||||
@@ -1422,7 +1422,7 @@ public class KotlinTypeMapper {
|
||||
List<ResolvedValueArgument> valueArguments = superCall.getValueArgumentsByIndex();
|
||||
assert valueArguments != null : "Failed to arrange value arguments by index: " + superDescriptor;
|
||||
|
||||
List<JvmMethodParameterSignature> parameters = mapSignatureSkipGeneric(superDescriptor).getValueParameters();
|
||||
List<JvmMethodParameterSignature> parameters = mapSignatureSkipGeneric(superDescriptor.getOriginal()).getValueParameters();
|
||||
|
||||
int params = parameters.size();
|
||||
int args = valueArguments.size();
|
||||
@@ -1504,4 +1504,13 @@ public class KotlinTypeMapper {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String classInternalName(@NotNull ClassDescriptor classDescriptor) {
|
||||
Type recordedType = typeMappingConfiguration.getPredefinedTypeForClass(classDescriptor);
|
||||
if (recordedType != null) {
|
||||
return recordedType.getInternalName();
|
||||
}
|
||||
return TypeSignatureMappingKt.computeInternalName(classDescriptor, typeMappingConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.serialization.builtins.BuiltInsProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.builtins.BuiltInsSerializerExtension
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment.Companion.DOT_METADATA_FILE_EXTENSION
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmPackageTable
|
||||
@@ -142,11 +141,11 @@ open class MetadataSerializer(private val dependOnOldBuiltIns: Boolean) {
|
||||
protected inner class PackageSerializer(
|
||||
private val classes: Collection<DeclarationDescriptor>,
|
||||
private val members: Collection<DeclarationDescriptor>,
|
||||
packageFqName: FqName,
|
||||
private val packageFqName: FqName,
|
||||
private val destFile: File
|
||||
) {
|
||||
private val proto = BuiltInsProtoBuf.BuiltIns.newBuilder()
|
||||
private val extension = BuiltInsSerializerExtension(packageFqName)
|
||||
private val proto = ProtoBuf.PackageFragment.newBuilder()
|
||||
private val extension = BuiltInsSerializerExtension()
|
||||
|
||||
fun run() {
|
||||
serializeClasses(classes)
|
||||
@@ -171,7 +170,7 @@ open class MetadataSerializer(private val dependOnOldBuiltIns: Boolean) {
|
||||
}
|
||||
|
||||
private fun serializeMembers(members: Collection<DeclarationDescriptor>) {
|
||||
proto.`package` = DescriptorSerializer.createTopLevel(extension).packagePartProto(members).build()
|
||||
proto.`package` = DescriptorSerializer.createTopLevel(extension).packagePartProto(packageFqName, members).build()
|
||||
}
|
||||
|
||||
private fun serializeStringTable() {
|
||||
|
||||
@@ -17,16 +17,8 @@
|
||||
package org.jetbrains.kotlin.serialization.builtins
|
||||
|
||||
import org.jetbrains.kotlin.builtins.BuiltInSerializerProtocol
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.serialization.KotlinSerializerExtensionBase
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
|
||||
class BuiltInsSerializerExtension(
|
||||
private val packageFqName: FqName
|
||||
) : KotlinSerializerExtensionBase(BuiltInSerializerProtocol) {
|
||||
class BuiltInsSerializerExtension : KotlinSerializerExtensionBase(BuiltInSerializerProtocol) {
|
||||
override fun shouldUseTypeTable(): Boolean = true
|
||||
|
||||
override fun serializePackage(proto: ProtoBuf.Package.Builder) {
|
||||
proto.setExtension(BuiltInsProtoBuf.packageFqName, stringTable.getPackageFqNameIndex(packageFqName))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.serialization.builtins
|
||||
|
||||
import com.intellij.util.concurrency.AppExecutorUtil
|
||||
import com.intellij.util.concurrency.AppScheduledExecutorService
|
||||
import java.io.File
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
@@ -37,19 +35,13 @@ found top-level declarations to <destination dir> (*.kotlin_builtins files)"""
|
||||
|
||||
val destDir = File(args[0])
|
||||
|
||||
val srcDirs = args.drop(1).map { File(it) }
|
||||
val srcDirs = args.drop(1).map(::File)
|
||||
assert(srcDirs.isNotEmpty()) { "At least one source directory should be specified" }
|
||||
|
||||
val missing = srcDirs.filterNot { it.exists() }
|
||||
val missing = srcDirs.filterNot(File::exists)
|
||||
assert(missing.isEmpty()) { "These source directories are missing: $missing" }
|
||||
|
||||
try {
|
||||
BuiltInsSerializer(dependOnOldBuiltIns = false).serialize(destDir, srcDirs, listOf()) { totalSize, totalFiles ->
|
||||
println("Total bytes written: $totalSize to $totalFiles files")
|
||||
}
|
||||
}
|
||||
finally {
|
||||
val service = AppExecutorUtil.getAppScheduledExecutorService() as AppScheduledExecutorService
|
||||
service.shutdownAppScheduledExecutorService()
|
||||
BuiltInsSerializer(dependOnOldBuiltIns = false).serialize(destDir, srcDirs, listOf()) { totalSize, totalFiles ->
|
||||
println("Total bytes written: $totalSize to $totalFiles files")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="util" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="intellij-core" level="project" />
|
||||
<orderEntry type="library" exported="" name="cli-parser" level="project" />
|
||||
<orderEntry type="library" name="jps" level="project" />
|
||||
<orderEntry type="module" module-name="descriptor.loader.java" />
|
||||
<orderEntry type="module" module-name="frontend.java" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -17,8 +17,8 @@
|
||||
package org.jetbrains.kotlin.cli.common.arguments;
|
||||
|
||||
import com.intellij.util.SmartList;
|
||||
import com.sampullara.cli.Argument;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
@@ -79,6 +79,9 @@ public abstract class CommonCompilerArguments implements Serializable {
|
||||
@Argument(value = "Xno-check-impl", description = "Do not check presence of 'impl' modifier in multi-platform projects")
|
||||
public boolean noCheckImpl;
|
||||
|
||||
@Argument(value = "Xskip-java-check", description = "Do not warn when running the compiler under Java 6 or 7")
|
||||
public boolean noJavaVersionWarning;
|
||||
|
||||
@Argument(value = "Xcoroutines=warn")
|
||||
public boolean coroutinesWarn;
|
||||
|
||||
@@ -96,6 +99,15 @@ public abstract class CommonCompilerArguments implements Serializable {
|
||||
|
||||
public List<String> unknownExtraFlags = new SmartList<String>();
|
||||
|
||||
@NotNull
|
||||
public static CommonCompilerArguments createDefaultInstance() {
|
||||
DummyImpl arguments = new DummyImpl();
|
||||
arguments.coroutinesEnable = false;
|
||||
arguments.coroutinesWarn = true;
|
||||
arguments.coroutinesError = false;
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String executableScriptFileName() {
|
||||
return "kotlinc";
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.cli.common.arguments;
|
||||
|
||||
import com.sampullara.cli.Argument;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument;
|
||||
|
||||
import static org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants.CALL;
|
||||
import static org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants.NO_CALL;
|
||||
@@ -71,6 +71,13 @@ public class K2JSCompilerArguments extends CommonCompilerArguments {
|
||||
@ValueDescription("<path>")
|
||||
public String outputPostfix;
|
||||
|
||||
@NotNull
|
||||
public static K2JSCompilerArguments createDefaultInstance() {
|
||||
K2JSCompilerArguments arguments = new K2JSCompilerArguments();
|
||||
arguments.moduleKind = K2JsArgumentConstants.MODULE_PLAIN;
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String executableScriptFileName() {
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.cli.common.arguments;
|
||||
|
||||
import com.sampullara.cli.Argument;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument;
|
||||
import org.jetbrains.kotlin.config.JvmTarget;
|
||||
|
||||
public class K2JVMCompilerArguments extends CommonCompilerArguments {
|
||||
public static final long serialVersionUID = 0L;
|
||||
@@ -113,10 +114,16 @@ public class K2JVMCompilerArguments extends CommonCompilerArguments {
|
||||
// Paths to output directories for friend modules.
|
||||
public String[] friendPaths;
|
||||
|
||||
@NotNull
|
||||
public static K2JVMCompilerArguments createDefaultInstance() {
|
||||
K2JVMCompilerArguments arguments = new K2JVMCompilerArguments();
|
||||
arguments.jvmTarget = JvmTarget.DEFAULT.getDescription();
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String executableScriptFileName() {
|
||||
return "kotlinc-jvm";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.cli.common.arguments;
|
||||
|
||||
import com.sampullara.cli.Argument;
|
||||
import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument;
|
||||
|
||||
public class K2MetadataCompilerArguments extends CommonCompilerArguments {
|
||||
public static final long serialVersionUID = 0L;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package org.jetbrains.kotlin.cli.common.arguments
|
||||
|
||||
import com.intellij.util.xmlb.XmlSerializerUtil
|
||||
import com.sampullara.cli.Args
|
||||
import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Args
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Modifier
|
||||
import java.util.*
|
||||
@@ -37,23 +37,23 @@ import java.util.*
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Any> copyBean(bean: T) = copyFields(bean, bean.javaClass.newInstance(), true, collectFieldsToCopy(bean.javaClass, false))
|
||||
fun <T : Any> copyBean(bean: T) = copyFields(bean, bean::class.java.newInstance(), true, collectFieldsToCopy(bean::class.java, false))
|
||||
|
||||
fun <From : Any, To : From> mergeBeans(from: From, to: To): To {
|
||||
// TODO: rewrite when updated version of com.intellij.util.xmlb is available on TeamCity
|
||||
return copyFields(from, XmlSerializerUtil.createCopy(to), false, collectFieldsToCopy(from.javaClass, false))
|
||||
return copyFields(from, XmlSerializerUtil.createCopy(to), false, collectFieldsToCopy(from::class.java, false))
|
||||
}
|
||||
|
||||
fun <From : Any, To : Any> copyInheritedFields(from: From, to: To) = copyFields(from, to, true, collectFieldsToCopy(from.javaClass, true))
|
||||
fun <From : Any, To : Any> copyInheritedFields(from: From, to: To) = copyFields(from, to, true, collectFieldsToCopy(from::class.java, true))
|
||||
|
||||
fun <From : Any, To : Any> copyFieldsSatisfying(from: From, to: To, predicate: (Field) -> Boolean) =
|
||||
copyFields(from, to, true, collectFieldsToCopy(from.javaClass, false).filter(predicate))
|
||||
copyFields(from, to, true, collectFieldsToCopy(from::class.java, false).filter(predicate))
|
||||
|
||||
private fun <From : Any, To : Any> copyFields(from: From, to: To, deepCopyWhenNeeded: Boolean, fieldsToCopy: List<Field>): To {
|
||||
if (from == to) return to
|
||||
|
||||
for (fromField in fieldsToCopy) {
|
||||
val toField = to.javaClass.getField(fromField.name)
|
||||
val toField = to::class.java.getField(fromField.name)
|
||||
val fromValue = fromField.get(from)
|
||||
toField.set(to, if (deepCopyWhenNeeded) fromValue?.copyValueIfNeeded() else fromValue)
|
||||
}
|
||||
@@ -72,14 +72,14 @@ private fun Any.copyValueIfNeeded(): Any {
|
||||
is DoubleArray -> Arrays.copyOf(this, size)
|
||||
is BooleanArray -> Arrays.copyOf(this, size)
|
||||
|
||||
is Array<*> -> java.lang.reflect.Array.newInstance(javaClass.componentType, size).apply {
|
||||
is Array<*> -> java.lang.reflect.Array.newInstance(this::class.java.componentType, size).apply {
|
||||
this as Array<Any?>
|
||||
(this@copyValueIfNeeded as Array<Any?>).forEachIndexed { i, value -> this[i] = value?.copyValueIfNeeded() }
|
||||
}
|
||||
|
||||
is MutableCollection<*> -> (this as Collection<Any?>).mapTo(javaClass.newInstance() as MutableCollection<Any?>) { it?.copyValueIfNeeded() }
|
||||
is MutableCollection<*> -> (this as Collection<Any?>).mapTo(this::class.java.newInstance() as MutableCollection<Any?>) { it?.copyValueIfNeeded() }
|
||||
|
||||
is MutableMap<*, *> -> (javaClass.newInstance() as MutableMap<Any?, Any?>).apply {
|
||||
is MutableMap<*, *> -> (this::class.java.newInstance() as MutableMap<Any?, Any?>).apply {
|
||||
for ((k, v) in this@copyValueIfNeeded.entries) {
|
||||
put(k?.copyValueIfNeeded(), v?.copyValueIfNeeded())
|
||||
}
|
||||
@@ -89,7 +89,7 @@ private fun Any.copyValueIfNeeded(): Any {
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectFieldsToCopy(clazz: Class<*>, inheritedOnly: Boolean): List<Field> {
|
||||
fun collectFieldsToCopy(clazz: Class<*>, inheritedOnly: Boolean): List<Field> {
|
||||
val fromFields = ArrayList<Field>()
|
||||
|
||||
var currentClass: Class<*>? = if (inheritedOnly) clazz.superclass else clazz
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user