mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-27 08:31:28 +00:00
Compare commits
352 Commits
script_run
...
1.1.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cb194c03f | ||
|
|
9191d38393 | ||
|
|
0dfe1a13a3 | ||
|
|
f9d74c858b | ||
|
|
d2f8942dda | ||
|
|
c656a7e244 | ||
|
|
393966d868 | ||
|
|
2aa6f5ab36 | ||
|
|
5ced60cf27 | ||
|
|
c46d3f4e99 | ||
|
|
bd2b0e576c | ||
|
|
87c3444ac7 | ||
|
|
1aebf44995 | ||
|
|
fab5f95420 | ||
|
|
56c06786e4 | ||
|
|
46d31b14ba | ||
|
|
a872b84785 | ||
|
|
6930a7cb46 | ||
|
|
9c288a65e7 | ||
|
|
5c9876f65e | ||
|
|
444604b589 | ||
|
|
758a79e8d1 | ||
|
|
ff4b8604da | ||
|
|
8092fe0ef6 | ||
|
|
1b688a3100 | ||
|
|
ba340aa3fe | ||
|
|
f82810b3ad | ||
|
|
72ca1338a2 | ||
|
|
438d35547a | ||
|
|
7a947ff026 | ||
|
|
f437cc4832 | ||
|
|
e98040ce76 | ||
|
|
ca259d7ddd | ||
|
|
ec92cb8733 | ||
|
|
c7d6ca0238 | ||
|
|
1ad2c716a5 | ||
|
|
df27f9d5d4 | ||
|
|
5bb98c5685 | ||
|
|
698b781726 | ||
|
|
0640fd43db | ||
|
|
23592cd549 | ||
|
|
9794ec70ae | ||
|
|
96e9545294 | ||
|
|
3ca24659a2 | ||
|
|
061741aab9 | ||
|
|
c77ac2da37 | ||
|
|
6089b9e459 | ||
|
|
94780418e7 | ||
|
|
a7685779f2 | ||
|
|
5131bb58a3 | ||
|
|
6e43210160 | ||
|
|
20e492e886 | ||
|
|
11889bda0b | ||
|
|
44a84889c0 | ||
|
|
df8ff29b07 | ||
|
|
d49767bbc6 | ||
|
|
9f950a2648 | ||
|
|
129b1c9521 | ||
|
|
b153b4c84e | ||
|
|
6bbe95d5bc | ||
|
|
9ee8c283ea | ||
|
|
34787901ed | ||
|
|
0b0d3db726 | ||
|
|
e8aadd25c0 | ||
|
|
21d9fc6782 | ||
|
|
2da7b7d3b6 | ||
|
|
743d662b80 | ||
|
|
89c4cae585 | ||
|
|
e32943571d | ||
|
|
7777f0b245 | ||
|
|
317e0948fa | ||
|
|
fbba4610e9 | ||
|
|
a5c684a969 | ||
|
|
8235c607dc | ||
|
|
af5c9efbd5 | ||
|
|
a4f5a0c918 | ||
|
|
2e6173e833 | ||
|
|
0a0a1c6fcd | ||
|
|
d70dfd457c | ||
|
|
9a80c0c7ab | ||
|
|
1cd723a552 | ||
|
|
5ca11db512 | ||
|
|
8b62b3ae55 | ||
|
|
3b42f4fff6 | ||
|
|
a8fdc88ac7 | ||
|
|
b15a441fc2 | ||
|
|
3a2fb489cb | ||
|
|
a208adf522 | ||
|
|
838a74d9de | ||
|
|
8e590d5913 | ||
|
|
aac8c19cf1 | ||
|
|
c49b55721b | ||
|
|
0f38b4636b | ||
|
|
93d9627054 | ||
|
|
2a4b6152a4 | ||
|
|
60e2e4911c | ||
|
|
92aa22aa9a | ||
|
|
674e0404d0 | ||
|
|
60f6754e0c | ||
|
|
cab7560089 | ||
|
|
7a1acaafad | ||
|
|
421962ab0f | ||
|
|
f43aa241da | ||
|
|
5d96a185bc | ||
|
|
166e81bd6d | ||
|
|
9fd7d949a4 | ||
|
|
b7a21e6cd8 | ||
|
|
62ba625247 | ||
|
|
c8fd0468f1 | ||
|
|
ba57d31391 | ||
|
|
878403bba4 | ||
|
|
d62e95f2d6 | ||
|
|
b8fbe1d808 | ||
|
|
d41fbcd285 | ||
|
|
12ed6c5ed2 | ||
|
|
b17ddb679c | ||
|
|
b24f272b99 | ||
|
|
008ff26687 | ||
|
|
f72bbfb527 | ||
|
|
22391b8737 | ||
|
|
28169a8a51 | ||
|
|
0396e5a9eb | ||
|
|
9c173bdd06 | ||
|
|
017bd3d9e0 | ||
|
|
336b3402a8 | ||
|
|
754733f514 | ||
|
|
85fbf3478d | ||
|
|
341eab5536 | ||
|
|
e1c12f3847 | ||
|
|
b08f36eabc | ||
|
|
114ea51232 | ||
|
|
7e3ea63586 | ||
|
|
91b05f6648 | ||
|
|
b2f0004a8b | ||
|
|
5b158f6d5a | ||
|
|
79212bbf2b | ||
|
|
f77bbf18d0 | ||
|
|
680462393f | ||
|
|
9cd56e691f | ||
|
|
54c74041b6 | ||
|
|
079f0ced7f | ||
|
|
eee5c1e836 | ||
|
|
fd411bdae1 | ||
|
|
95264f818d | ||
|
|
a1fd1726ce | ||
|
|
3b4b9c15d5 | ||
|
|
fabb150abc | ||
|
|
ce8943975e | ||
|
|
103c23250a | ||
|
|
cd380e6407 | ||
|
|
0f82e76e9b | ||
|
|
8b95973f6a | ||
|
|
92a49239b4 | ||
|
|
ed23880d60 | ||
|
|
756872a878 | ||
|
|
d245ff328c | ||
|
|
3f35fd3dcd | ||
|
|
4b3ead85d9 | ||
|
|
457fad7146 | ||
|
|
3f71b1af4f | ||
|
|
0203243fe0 | ||
|
|
f0a5fab759 | ||
|
|
444f14371d | ||
|
|
9d2d0c61d5 | ||
|
|
51f85aa8a5 | ||
|
|
22ea5a0679 | ||
|
|
b7f4a583cf | ||
|
|
fcb81c8c06 | ||
|
|
cf39aed382 | ||
|
|
39c3733786 | ||
|
|
cbbf796be2 | ||
|
|
b577a087ff | ||
|
|
d2192447ff | ||
|
|
0d55ab0750 | ||
|
|
6612f57767 | ||
|
|
f6777e8af9 | ||
|
|
0383370588 | ||
|
|
01779f10c3 | ||
|
|
aebc35a8f7 | ||
|
|
ae6973b8e4 | ||
|
|
6325fb1455 | ||
|
|
1efeec513f | ||
|
|
6c43e3f46b | ||
|
|
1558f81e1f | ||
|
|
70a0ca5b24 | ||
|
|
517e226ceb | ||
|
|
dee73deb28 | ||
|
|
e8bb5f7a47 | ||
|
|
0e0d429810 | ||
|
|
cee07c769e | ||
|
|
7823bee0a2 | ||
|
|
ea26411f86 | ||
|
|
94b51d8be0 | ||
|
|
935cf4d352 | ||
|
|
369d03d3f4 | ||
|
|
fae73c5b6e | ||
|
|
7faebbaadf | ||
|
|
6fe94b33fe | ||
|
|
e0b200a2fc | ||
|
|
83890dea47 | ||
|
|
a05abc0f1b | ||
|
|
9fa065142b | ||
|
|
aac8c847f7 | ||
|
|
fa9086e994 | ||
|
|
91cc4df61a | ||
|
|
ef3fb6e744 | ||
|
|
2a67ad5957 | ||
|
|
84547b535a | ||
|
|
cf3a2a6072 | ||
|
|
61f8931080 | ||
|
|
0f6b8d6d24 | ||
|
|
c2398cfc79 | ||
|
|
8f6e990b34 | ||
|
|
68ec640421 | ||
|
|
00ed7d37e0 | ||
|
|
22945c8adf | ||
|
|
9a44ad14b7 | ||
|
|
b874c92ea4 | ||
|
|
89484720a9 | ||
|
|
9afad21355 | ||
|
|
2ef1c2638d | ||
|
|
4aea15253b | ||
|
|
092f498c87 | ||
|
|
0052a60102 | ||
|
|
271b03e709 | ||
|
|
5085082882 | ||
|
|
e8c55ff562 | ||
|
|
3ac20bb452 | ||
|
|
c5b9c208b4 | ||
|
|
8e046c937a | ||
|
|
f4f6c1f9a8 | ||
|
|
bc17f4a037 | ||
|
|
3525d7b114 | ||
|
|
154939a2b0 | ||
|
|
a15ad448fa | ||
|
|
728db429df | ||
|
|
96a650085c | ||
|
|
09ecacabae | ||
|
|
8887728cae | ||
|
|
246d958b7a | ||
|
|
8a0f296e4f | ||
|
|
4cc8cdd603 | ||
|
|
7d8a66bd7e | ||
|
|
7366f6f885 | ||
|
|
c61453dfe4 | ||
|
|
1c2d598ad8 | ||
|
|
d25c2b321f | ||
|
|
9bae9ef919 | ||
|
|
f27ab21489 | ||
|
|
fff44b9a86 | ||
|
|
6af24876f9 | ||
|
|
9cff205755 | ||
|
|
e24becab2a | ||
|
|
989fe6197d | ||
|
|
dafc0d3eef | ||
|
|
f0327ca99d | ||
|
|
1f928ded2d | ||
|
|
cf00d29b0d | ||
|
|
cb2b038f26 | ||
|
|
9047547f8d | ||
|
|
aa8713953b | ||
|
|
51cfd9cda8 | ||
|
|
9f8557d782 | ||
|
|
22710fdd72 | ||
|
|
1a450eaad0 | ||
|
|
deb5fe104c | ||
|
|
04f707f8f8 | ||
|
|
fb9f0e8b3f | ||
|
|
f94d8145e2 | ||
|
|
e6e5f14c12 | ||
|
|
fca0f9da29 | ||
|
|
11004ed7a0 | ||
|
|
7f16ac6155 | ||
|
|
420747ef79 | ||
|
|
0f7e48aeef | ||
|
|
bab228a111 | ||
|
|
e8ea1968ec | ||
|
|
ecf69556d6 | ||
|
|
5ac69ed138 | ||
|
|
8238785405 | ||
|
|
2ec1e5aff9 | ||
|
|
9e27416df4 | ||
|
|
4c0f1e1dd8 | ||
|
|
fa52e816e8 | ||
|
|
110314c0c1 | ||
|
|
4b50020acc | ||
|
|
bc8fc980e1 | ||
|
|
5a0b269f91 | ||
|
|
3e875d017f | ||
|
|
b4683315f6 | ||
|
|
c42299a37f | ||
|
|
432f0ba0f4 | ||
|
|
fbf9bc7a07 | ||
|
|
8d9adfda7c | ||
|
|
b62cb188f7 | ||
|
|
51bac281f5 | ||
|
|
9cb7cba8ed | ||
|
|
a3e439c51b | ||
|
|
04984e5d1a | ||
|
|
af86bc314d | ||
|
|
c316a9922b | ||
|
|
b785d38f06 | ||
|
|
f489311884 | ||
|
|
522bd3abe8 | ||
|
|
cc2a6fc683 | ||
|
|
dcc7e94493 | ||
|
|
6a924c57cd | ||
|
|
e6403e8e97 | ||
|
|
06887e4f90 | ||
|
|
dbf2a0cb88 | ||
|
|
ab7a945eee | ||
|
|
a06ae76487 | ||
|
|
702eb3d921 | ||
|
|
952c276c01 | ||
|
|
9f1bd71780 | ||
|
|
2dbb6f8f2a | ||
|
|
9855b9a268 | ||
|
|
967d16547d | ||
|
|
30a976f75a | ||
|
|
e356c460b0 | ||
|
|
ec8295e674 | ||
|
|
83c8a92f6b | ||
|
|
42abb2ccf8 | ||
|
|
67e4833b11 | ||
|
|
976afd2f77 | ||
|
|
0cd618103f | ||
|
|
424fd67f9e | ||
|
|
021d7c17e4 | ||
|
|
119124a79c | ||
|
|
c2972a53e7 | ||
|
|
60e34ca808 | ||
|
|
e5a5d72e00 | ||
|
|
d11ee91d03 | ||
|
|
48cf1f05a7 | ||
|
|
26f3174d09 | ||
|
|
06d60b53b2 | ||
|
|
c3aeabed8c | ||
|
|
18b374ccba | ||
|
|
668e882db2 | ||
|
|
7f135ce137 | ||
|
|
1605475cc4 | ||
|
|
0eb102f332 | ||
|
|
59b9d0a5ad | ||
|
|
f54dcb3b3f | ||
|
|
453cd2e615 | ||
|
|
4e43cc6bb6 | ||
|
|
5cdb2d80bd | ||
|
|
4f618353ad | ||
|
|
1dcb888d6d | ||
|
|
f28d21bc6d | ||
|
|
91417cc4e5 | ||
|
|
132b588af7 |
1
.idea/artifacts/KotlinPlugin.xml
generated
1
.idea/artifacts/KotlinPlugin.xml
generated
@@ -61,6 +61,7 @@
|
||||
<element id="module-output" name="ir.psi2ir" />
|
||||
<element id="module-output" name="annotation-based-compiler-plugins-ide-support" />
|
||||
<element id="module-output" name="frontend.script" />
|
||||
<element id="extracted-dir" path="$PROJECT_DIR$/dependencies/json-org.jar" path-in-jar="/" />
|
||||
</element>
|
||||
<element id="library" level="project" name="javax.inject" />
|
||||
<element id="directory" name="jps">
|
||||
|
||||
2
.idea/dictionaries/yan.xml
generated
2
.idea/dictionaries/yan.xml
generated
@@ -1,8 +1,10 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="yan">
|
||||
<words>
|
||||
<w>deserializes</w>
|
||||
<w>impls</w>
|
||||
<w>kapt</w>
|
||||
<w>parceler</w>
|
||||
<w>uast</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
|
||||
2
.idea/libraries/intellij_core.xml
generated
2
.idea/libraries/intellij_core.xml
generated
@@ -18,14 +18,12 @@
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/core/util.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/core/xpp3-1.1.4-min.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/core/xstream-1.4.8.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/lib/jsr305.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/guava-19.0-sources.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/sources/sources.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/asm-src.zip!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/lib/jsr305.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
59
.idea/libraries/robolectric.xml
generated
Normal file
59
.idea/libraries/robolectric.xml
generated
Normal file
@@ -0,0 +1,59 @@
|
||||
<component name="libraryTable">
|
||||
<library name="robolectric">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/accessibility-test-framework-2.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/ant-1.8.0.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/ant-launcher-1.8.0.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/asm-5.0.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/asm-commons-5.0.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/asm-tree-5.0.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/assertj-core-2.6.0.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/backport-util-concurrent-3.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/bcprov-jdk16-1.46.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/classworlds-1.1-alpha-2.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/guava-20.0.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/hamcrest-core-1.3.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/hamcrest-library-1.3.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/icu4j-53.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-ant-tasks-2.1.3.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-artifact-2.2.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-artifact-manager-2.2.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-error-diagnostics-2.2.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-model-2.2.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-plugin-registry-2.2.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-profile-2.2.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-project-2.2.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-repository-metadata-2.2.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/maven-settings-2.2.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/nekohtml-1.9.6.2.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/plexus-container-default-1.0-alpha-9-stable-1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/plexus-interpolation-1.11.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/plexus-utils-1.5.15.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/protobuf-java-2.6.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-3.3.2.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-annotations-3.3.2.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-junit-3.3.2.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-resources-3.3.2.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-sandbox-3.3.2.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-utils-3.3.2.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/shadow-api-3.3.2.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/shadows-core-3.3.2.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/sqlite4java-0.282.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/wagon-file-1.0-beta-6.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/wagon-http-lightweight-1.0-beta-6.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/wagon-http-shared-1.0-beta-6.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/wagon-provider-api-1.0-beta-6.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/xercesMinimal-1.9.6.2.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/xmlpull-1.1.3.1.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/xpp3_min-1.1.4c.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/xstream-1.4.8.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-3.3.2-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-3.3.2-sources-source.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/robolectric/robolectric-3.3.2-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
3211
ChangeLog.md
3211
ChangeLog.md
File diff suppressed because it is too large
Load Diff
@@ -22202,8 +22202,8 @@ public final class DebugProtoBuf {
|
||||
* <code>optional int32 flags = 1 [default = 0];</code>
|
||||
*
|
||||
* <pre>
|
||||
*hasAnnotations
|
||||
*declaresDefault
|
||||
*hasAnnotations
|
||||
*isCrossinline
|
||||
*isNoinline
|
||||
* </pre>
|
||||
@@ -22213,8 +22213,8 @@ public final class DebugProtoBuf {
|
||||
* <code>optional int32 flags = 1 [default = 0];</code>
|
||||
*
|
||||
* <pre>
|
||||
*hasAnnotations
|
||||
*declaresDefault
|
||||
*hasAnnotations
|
||||
*isCrossinline
|
||||
*isNoinline
|
||||
* </pre>
|
||||
@@ -22419,8 +22419,8 @@ public final class DebugProtoBuf {
|
||||
* <code>optional int32 flags = 1 [default = 0];</code>
|
||||
*
|
||||
* <pre>
|
||||
*hasAnnotations
|
||||
*declaresDefault
|
||||
*hasAnnotations
|
||||
*isCrossinline
|
||||
*isNoinline
|
||||
* </pre>
|
||||
@@ -22432,8 +22432,8 @@ public final class DebugProtoBuf {
|
||||
* <code>optional int32 flags = 1 [default = 0];</code>
|
||||
*
|
||||
* <pre>
|
||||
*hasAnnotations
|
||||
*declaresDefault
|
||||
*hasAnnotations
|
||||
*isCrossinline
|
||||
*isNoinline
|
||||
* </pre>
|
||||
@@ -22913,8 +22913,8 @@ public final class DebugProtoBuf {
|
||||
* <code>optional int32 flags = 1 [default = 0];</code>
|
||||
*
|
||||
* <pre>
|
||||
*hasAnnotations
|
||||
*declaresDefault
|
||||
*hasAnnotations
|
||||
*isCrossinline
|
||||
*isNoinline
|
||||
* </pre>
|
||||
@@ -22926,8 +22926,8 @@ public final class DebugProtoBuf {
|
||||
* <code>optional int32 flags = 1 [default = 0];</code>
|
||||
*
|
||||
* <pre>
|
||||
*hasAnnotations
|
||||
*declaresDefault
|
||||
*hasAnnotations
|
||||
*isCrossinline
|
||||
*isNoinline
|
||||
* </pre>
|
||||
@@ -22939,8 +22939,8 @@ public final class DebugProtoBuf {
|
||||
* <code>optional int32 flags = 1 [default = 0];</code>
|
||||
*
|
||||
* <pre>
|
||||
*hasAnnotations
|
||||
*declaresDefault
|
||||
*hasAnnotations
|
||||
*isCrossinline
|
||||
*isNoinline
|
||||
* </pre>
|
||||
@@ -22955,8 +22955,8 @@ public final class DebugProtoBuf {
|
||||
* <code>optional int32 flags = 1 [default = 0];</code>
|
||||
*
|
||||
* <pre>
|
||||
*hasAnnotations
|
||||
*declaresDefault
|
||||
*hasAnnotations
|
||||
*isCrossinline
|
||||
*isNoinline
|
||||
* </pre>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.annotation.WrappedAnnotated;
|
||||
@@ -26,7 +25,6 @@ import org.jetbrains.kotlin.descriptors.annotations.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.resolve.AnnotationChecker;
|
||||
import org.jetbrains.kotlin.resolve.constants.*;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
@@ -293,27 +291,32 @@ public abstract class AnnotationCodegen {
|
||||
|
||||
@Nullable
|
||||
private String genAnnotation(@NotNull AnnotationDescriptor annotationDescriptor) {
|
||||
ClassDescriptor classDescriptor = getAnnotationClass(annotationDescriptor);
|
||||
assert classDescriptor != null : "Annotation descriptor has no class: " + annotationDescriptor;
|
||||
RetentionPolicy rp = getRetentionPolicy(classDescriptor);
|
||||
ClassifierDescriptor classifierDescriptor = getAnnotationClass(annotationDescriptor);
|
||||
assert classifierDescriptor != null : "Annotation descriptor has no class: " + annotationDescriptor;
|
||||
RetentionPolicy rp = getRetentionPolicy(classifierDescriptor);
|
||||
if (rp == RetentionPolicy.SOURCE && !typeMapper.getClassBuilderMode().generateSourceRetentionAnnotations) {
|
||||
return null;
|
||||
}
|
||||
|
||||
innerClassConsumer.addInnerClassInfoFromAnnotation(classDescriptor);
|
||||
String descriptor = typeMapper.mapType(annotationDescriptor.getType()).getDescriptor();
|
||||
|
||||
String asmTypeDescriptor = typeMapper.mapType(annotationDescriptor.getType()).getDescriptor();
|
||||
AnnotationVisitor annotationVisitor = visitAnnotation(asmTypeDescriptor, rp == RetentionPolicy.RUNTIME);
|
||||
if (classifierDescriptor instanceof ClassDescriptor) {
|
||||
innerClassConsumer.addInnerClassInfoFromAnnotation(((ClassDescriptor) classifierDescriptor));
|
||||
}
|
||||
|
||||
AnnotationVisitor annotationVisitor = visitAnnotation(descriptor, rp == RetentionPolicy.RUNTIME);
|
||||
|
||||
genAnnotationArguments(annotationDescriptor, annotationVisitor);
|
||||
annotationVisitor.visitEnd();
|
||||
|
||||
return asmTypeDescriptor;
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
private void genAnnotationArguments(AnnotationDescriptor annotationDescriptor, AnnotationVisitor annotationVisitor) {
|
||||
for (Map.Entry<Name, ConstantValue<?>> entry : annotationDescriptor.getAllValueArguments().entrySet()) {
|
||||
genCompileTimeValue(entry.getKey().asString(), entry.getValue(), annotationVisitor);
|
||||
for (Map.Entry<ValueParameterDescriptor, ConstantValue<?>> entry : annotationDescriptor.getAllValueArguments().entrySet()) {
|
||||
ValueParameterDescriptor descriptor = entry.getKey();
|
||||
String name = descriptor.getName().asString();
|
||||
genCompileTimeValue(name, entry.getValue(), annotationVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,13 +475,16 @@ public abstract class AnnotationCodegen {
|
||||
}
|
||||
AnnotationDescriptor retentionAnnotation = descriptor.getAnnotations().findAnnotation(new FqName(Retention.class.getName()));
|
||||
if (retentionAnnotation != null) {
|
||||
ConstantValue<?> compileTimeConstant = CollectionsKt.firstOrNull(retentionAnnotation.getAllValueArguments().values());
|
||||
if (compileTimeConstant instanceof EnumValue) {
|
||||
ClassDescriptor enumEntry = ((EnumValue) compileTimeConstant).getValue();
|
||||
KotlinType classObjectType = DescriptorUtilsKt.getClassValueType(enumEntry);
|
||||
if (classObjectType != null) {
|
||||
if ("java/lang/annotation/RetentionPolicy".equals(typeMapper.mapType(classObjectType).getInternalName())) {
|
||||
return RetentionPolicy.valueOf(enumEntry.getName().asString());
|
||||
Collection<ConstantValue<?>> valueArguments = retentionAnnotation.getAllValueArguments().values();
|
||||
if (!valueArguments.isEmpty()) {
|
||||
ConstantValue<?> compileTimeConstant = valueArguments.iterator().next();
|
||||
if (compileTimeConstant instanceof EnumValue) {
|
||||
ClassDescriptor enumEntry = ((EnumValue) compileTimeConstant).getValue();
|
||||
KotlinType classObjectType = DescriptorUtilsKt.getClassValueType(enumEntry);
|
||||
if (classObjectType != null) {
|
||||
if ("java/lang/annotation/RetentionPolicy".equals(typeMapper.mapType(classObjectType).getInternalName())) {
|
||||
return RetentionPolicy.valueOf(enumEntry.getName().asString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,18 +140,10 @@ public class AsmUtil {
|
||||
return primitiveTypeByBoxedType.get(boxedType);
|
||||
}
|
||||
|
||||
public static boolean isBoxedTypeOf(@NotNull Type boxedType, @NotNull Type unboxedType) {
|
||||
return unboxPrimitiveTypeOrNull(boxedType) == unboxedType;
|
||||
}
|
||||
|
||||
public static boolean isIntPrimitive(Type type) {
|
||||
return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE;
|
||||
}
|
||||
|
||||
public static boolean isIntOrLongPrimitive(Type type) {
|
||||
return isIntPrimitive(type) || type == Type.LONG_TYPE;
|
||||
}
|
||||
|
||||
public static boolean isNumberPrimitiveOrBoolean(Type type) {
|
||||
return isNumberPrimitive(type) || type.getSort() == Type.BOOLEAN;
|
||||
}
|
||||
@@ -717,7 +709,7 @@ public class AsmUtil {
|
||||
if (innerType.getSort() == Type.OBJECT || innerType.getSort() == Type.ARRAY) {
|
||||
v.dup();
|
||||
v.visitLdcInsn(runtimeAssertionInfo.getMessage());
|
||||
v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkExpressionValueIsNotNull",
|
||||
v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkExpressionValueIsNotNull",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;)V", false);
|
||||
}
|
||||
StackValue.coerce(innerType, type, v);
|
||||
@@ -807,16 +799,6 @@ public class AsmUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void pop2(@NotNull MethodVisitor v, @NotNull Type type) {
|
||||
if (type.getSize() == 2) {
|
||||
v.visitInsn(Opcodes.POP2);
|
||||
v.visitInsn(Opcodes.POP2);
|
||||
}
|
||||
else {
|
||||
v.visitInsn(Opcodes.POP2);
|
||||
}
|
||||
}
|
||||
|
||||
public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) {
|
||||
dup(v, type.getSize());
|
||||
}
|
||||
@@ -833,22 +815,6 @@ public class AsmUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void dupx(@NotNull InstructionAdapter v, @NotNull Type type) {
|
||||
dupx(v, type.getSize());
|
||||
}
|
||||
|
||||
private static void dupx(@NotNull InstructionAdapter v, int size) {
|
||||
if (size == 2) {
|
||||
v.dup2X2();
|
||||
}
|
||||
else if (size == 1) {
|
||||
v.dupX1();
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void dup(@NotNull InstructionAdapter v, @NotNull Type topOfStack, @NotNull Type afterTop) {
|
||||
if (topOfStack.getSize() == 0 && afterTop.getSize() == 0) {
|
||||
return;
|
||||
|
||||
@@ -1,308 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
abstract class NumberLikeCompare(
|
||||
left: StackValue,
|
||||
right: StackValue,
|
||||
operandType: Type,
|
||||
private val opToken: IElementType
|
||||
) : BranchedValue(left, right, operandType, NumberCompare.getNumberCompareOpcode(opToken)) {
|
||||
override fun patchOpcode(opcode: Int, v: InstructionAdapter): Int =
|
||||
NumberCompare.patchOpcode(opcode, v, opToken, operandType)
|
||||
}
|
||||
|
||||
abstract class SafeCallFusedWithPrimitiveEqualityBase(
|
||||
opToken: IElementType,
|
||||
operandType: Type,
|
||||
left: StackValue,
|
||||
right: StackValue
|
||||
) : NumberLikeCompare(left, right, operandType, opToken) {
|
||||
private val trueIfEqual = opToken == KtTokens.EQEQ || opToken == KtTokens.EQEQEQ
|
||||
|
||||
protected abstract fun cleanupOnNullReceiver(v: InstructionAdapter)
|
||||
|
||||
override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
|
||||
val endLabel = Label()
|
||||
|
||||
arg1.put(operandType, v)
|
||||
arg2!!.put(operandType, v)
|
||||
v.visitJumpInsn(patchOpcode(if (jumpIfFalse) opcode else negatedOperations[opcode]!!, v), jumpLabel)
|
||||
v.goTo(endLabel)
|
||||
|
||||
cleanupOnNullReceiver(v)
|
||||
if (jumpIfFalse == trueIfEqual) {
|
||||
v.goTo(jumpLabel)
|
||||
}
|
||||
|
||||
v.mark(endLabel)
|
||||
}
|
||||
|
||||
override fun putSelector(type: Type, v: InstructionAdapter) {
|
||||
val falseLabel = Label()
|
||||
val endLabel = Label()
|
||||
|
||||
arg1.put(operandType, v)
|
||||
arg2!!.put(operandType, v)
|
||||
v.visitJumpInsn(patchOpcode(opcode, v), falseLabel)
|
||||
|
||||
if (!trueIfEqual) {
|
||||
val trueLabel = Label()
|
||||
v.goTo(trueLabel)
|
||||
cleanupOnNullReceiver(v)
|
||||
v.mark(trueLabel)
|
||||
}
|
||||
|
||||
v.iconst(1)
|
||||
v.goTo(endLabel)
|
||||
|
||||
if (trueIfEqual) {
|
||||
cleanupOnNullReceiver(v)
|
||||
}
|
||||
|
||||
v.mark(falseLabel)
|
||||
v.iconst(0)
|
||||
|
||||
v.mark(endLabel)
|
||||
coerceTo(type, v)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SafeCallToPrimitiveEquality(
|
||||
opToken: IElementType,
|
||||
operandType: Type,
|
||||
left: StackValue,
|
||||
right: StackValue,
|
||||
private val safeReceiverType: Type,
|
||||
private val safeReceiverIsNull: Label
|
||||
) : SafeCallFusedWithPrimitiveEqualityBase(opToken, operandType, left, right) {
|
||||
override fun cleanupOnNullReceiver(v: InstructionAdapter) {
|
||||
v.mark(safeReceiverIsNull)
|
||||
AsmUtil.pop(v, safeReceiverType)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PrimitiveToSafeCallEquality(
|
||||
opToken: IElementType,
|
||||
operandType: Type,
|
||||
left: StackValue,
|
||||
right: StackValue,
|
||||
private val safeReceiverType: Type,
|
||||
private val safeReceiverIsNull: Label
|
||||
) : SafeCallFusedWithPrimitiveEqualityBase(opToken, operandType, left, right) {
|
||||
override fun cleanupOnNullReceiver(v: InstructionAdapter) {
|
||||
v.mark(safeReceiverIsNull)
|
||||
AsmUtil.pop(v, safeReceiverType)
|
||||
AsmUtil.pop(v, arg1.type)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class BoxedToPrimitiveEquality private constructor(
|
||||
leftBoxed: StackValue,
|
||||
rightPrimitive: StackValue,
|
||||
primitiveType: Type,
|
||||
private val frameMap: FrameMap
|
||||
) : NumberLikeCompare(leftBoxed, rightPrimitive, primitiveType, KtTokens.EQEQ) {
|
||||
private val boxedType = arg1.type
|
||||
|
||||
override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
|
||||
if (arg2!!.canHaveSideEffects()) {
|
||||
val tmp = frameMap.enterTemp(operandType)
|
||||
doJump(
|
||||
v, jumpLabel, jumpIfFalse,
|
||||
{
|
||||
arg1.put(boxedType, v)
|
||||
arg2.put(operandType, v)
|
||||
v.store(tmp, operandType)
|
||||
},
|
||||
{ v.load(tmp, operandType) }
|
||||
)
|
||||
frameMap.leaveTemp(operandType)
|
||||
}
|
||||
else {
|
||||
doJump(
|
||||
v, jumpLabel, jumpIfFalse,
|
||||
{ arg1.put(boxedType, v) },
|
||||
{ arg2.put(operandType, v) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun doJump(
|
||||
v: InstructionAdapter,
|
||||
jumpLabel: Label,
|
||||
jumpIfFalse: Boolean,
|
||||
putArg1: () -> Unit,
|
||||
putArg2: () -> Unit
|
||||
) {
|
||||
val notNullLabel = Label()
|
||||
val endLabel = Label()
|
||||
|
||||
putArg1()
|
||||
AsmUtil.dup(v, boxedType)
|
||||
v.ifnonnull(notNullLabel)
|
||||
|
||||
AsmUtil.pop(v, boxedType)
|
||||
if (jumpIfFalse) v.goTo(jumpLabel) else v.goTo(endLabel)
|
||||
|
||||
v.mark(notNullLabel)
|
||||
coerce(boxedType, operandType, v)
|
||||
putArg2()
|
||||
v.visitJumpInsn(patchOpcode(if (jumpIfFalse) opcode else negatedOperations[opcode]!!, v), jumpLabel)
|
||||
|
||||
v.mark(endLabel)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun create(
|
||||
opToken: IElementType,
|
||||
left: StackValue,
|
||||
leftType: Type,
|
||||
right: StackValue,
|
||||
rightType: Type,
|
||||
frameMap: FrameMap
|
||||
): BranchedValue =
|
||||
if (!isApplicable(opToken, leftType, rightType))
|
||||
throw IllegalArgumentException("Not applicable for $opToken, $leftType, $rightType")
|
||||
else when (opToken) {
|
||||
KtTokens.EQEQ -> BoxedToPrimitiveEquality(left, right, rightType, frameMap)
|
||||
KtTokens.EXCLEQ -> Invert(BoxedToPrimitiveEquality(left, right, rightType, frameMap))
|
||||
else -> throw AssertionError("Unexpected opToken: $opToken")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isApplicable(opToken: IElementType, leftType: Type, rightType: Type) =
|
||||
(opToken == KtTokens.EQEQ || opToken == KtTokens.EXCLEQ) &&
|
||||
AsmUtil.isIntOrLongPrimitive(rightType) &&
|
||||
AsmUtil.isBoxedTypeOf(leftType, rightType)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PrimitiveToSomethingEquality
|
||||
protected constructor(
|
||||
leftPrimitive: StackValue,
|
||||
right: StackValue,
|
||||
primitiveType: Type
|
||||
) : NumberLikeCompare(leftPrimitive, right, primitiveType, KtTokens.EQEQ) {
|
||||
protected val primitiveType = leftPrimitive.type
|
||||
protected val rightType = right.type
|
||||
|
||||
override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
|
||||
val notNullLabel = Label()
|
||||
val endLabel = Label()
|
||||
|
||||
arg1.put(primitiveType, v)
|
||||
arg2!!.put(rightType, v)
|
||||
AsmUtil.dup(v, rightType)
|
||||
jumpIfCanCompareTopWithPrimitive(v, notNullLabel)
|
||||
|
||||
AsmUtil.pop(v, rightType)
|
||||
AsmUtil.pop(v, primitiveType)
|
||||
if (jumpIfFalse) v.goTo(jumpLabel) else v.goTo(endLabel)
|
||||
|
||||
v.mark(notNullLabel)
|
||||
coerceRightToPrimitive(v)
|
||||
v.visitJumpInsn(patchOpcode(if (jumpIfFalse) opcode else negatedOperations[opcode]!!, v), jumpLabel)
|
||||
|
||||
v.mark(endLabel)
|
||||
}
|
||||
|
||||
protected abstract fun jumpIfCanCompareTopWithPrimitive(v: InstructionAdapter, label: Label)
|
||||
protected abstract fun coerceRightToPrimitive(v: InstructionAdapter)
|
||||
}
|
||||
|
||||
|
||||
class PrimitiveToBoxedEquality private constructor(
|
||||
leftPrimitive: StackValue,
|
||||
rightBoxed: StackValue,
|
||||
primitiveType: Type
|
||||
) : PrimitiveToSomethingEquality(leftPrimitive, rightBoxed, primitiveType) {
|
||||
private val boxedType = rightBoxed.type
|
||||
|
||||
override fun jumpIfCanCompareTopWithPrimitive(v: InstructionAdapter, label: Label) {
|
||||
v.ifnonnull(label)
|
||||
}
|
||||
|
||||
override fun coerceRightToPrimitive(v: InstructionAdapter) {
|
||||
coerce(boxedType, primitiveType, v)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun create(opToken: IElementType, left: StackValue, leftType: Type, right: StackValue, rightType: Type): BranchedValue =
|
||||
if (!isApplicable(opToken, leftType, rightType))
|
||||
throw IllegalArgumentException("Not applicable for $opToken, $leftType, $rightType")
|
||||
else when (opToken) {
|
||||
KtTokens.EQEQ -> PrimitiveToBoxedEquality(left, right, leftType)
|
||||
KtTokens.EXCLEQ -> Invert(PrimitiveToBoxedEquality(left, right, leftType))
|
||||
else -> throw AssertionError("Unexpected opToken: $opToken")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isApplicable(opToken: IElementType, leftType: Type, rightType: Type) =
|
||||
(opToken == KtTokens.EQEQ || opToken == KtTokens.EXCLEQ) &&
|
||||
AsmUtil.isIntOrLongPrimitive(leftType) &&
|
||||
AsmUtil.isBoxedTypeOf(rightType, leftType)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PrimitiveToObjectEquality private constructor(
|
||||
leftPrimitive: StackValue,
|
||||
rightObject: StackValue,
|
||||
primitiveType: Type
|
||||
) : PrimitiveToSomethingEquality(leftPrimitive, rightObject, primitiveType) {
|
||||
private val boxedType = AsmUtil.boxType(primitiveType)
|
||||
|
||||
override fun jumpIfCanCompareTopWithPrimitive(v: InstructionAdapter, label: Label) {
|
||||
v.instanceOf(boxedType)
|
||||
v.ifne(label)
|
||||
}
|
||||
|
||||
override fun coerceRightToPrimitive(v: InstructionAdapter) {
|
||||
coerce(rightType, boxedType, v)
|
||||
coerce(boxedType, primitiveType, v)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun create(opToken: IElementType, left: StackValue, leftType: Type, right: StackValue, rightType: Type): BranchedValue =
|
||||
if (!isApplicable(opToken, leftType, rightType))
|
||||
throw IllegalArgumentException("Not applicable for $opToken, $leftType, $rightType")
|
||||
else when (opToken) {
|
||||
KtTokens.EQEQ -> PrimitiveToObjectEquality(left, right, leftType)
|
||||
KtTokens.EXCLEQ -> Invert(PrimitiveToObjectEquality(left, right, leftType))
|
||||
else -> throw AssertionError("Unexpected opToken: $opToken")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isApplicable(opToken: IElementType, leftType: Type, rightType: Type) =
|
||||
(opToken == KtTokens.EQEQ || opToken == KtTokens.EXCLEQ) &&
|
||||
AsmUtil.isIntOrLongPrimitive(leftType) &&
|
||||
rightType.sort == Type.OBJECT
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,9 @@ open class BranchedValue(
|
||||
condJump(jumpLabel, v, jumpIfFalse)
|
||||
}
|
||||
|
||||
protected open fun patchOpcode(opcode: Int, v: InstructionAdapter): Int = opcode
|
||||
protected open fun patchOpcode(opcode: Int, v: InstructionAdapter): Int {
|
||||
return opcode
|
||||
}
|
||||
|
||||
companion object {
|
||||
val negatedOperations = hashMapOf<Int, Int>()
|
||||
@@ -118,9 +120,13 @@ open class BranchedValue(
|
||||
negatedOperations.put(negatedOp, op)
|
||||
}
|
||||
|
||||
fun booleanConstant(value: Boolean): BranchedValue = if (value) TRUE else FALSE
|
||||
fun booleanConstant(value: Boolean): BranchedValue {
|
||||
return if (value) TRUE else FALSE
|
||||
}
|
||||
|
||||
fun createInvertValue(argument: StackValue): StackValue = Invert(condJump(argument))
|
||||
fun createInvertValue(argument: StackValue): StackValue {
|
||||
return Invert(condJump(argument))
|
||||
}
|
||||
|
||||
fun condJump(condition: StackValue, label: Label, jumpIfFalse: Boolean, iv: InstructionAdapter) {
|
||||
condJump(condition).condJump(label, iv, jumpIfFalse)
|
||||
@@ -130,11 +136,14 @@ open class BranchedValue(
|
||||
condJump(condition).loopJump(label, iv, jumpIfFalse)
|
||||
}
|
||||
|
||||
fun condJump(condition: StackValue): CondJump =
|
||||
CondJump(
|
||||
condition as? BranchedValue ?: BranchedValue(condition, null, Type.BOOLEAN_TYPE, IFEQ),
|
||||
IFEQ
|
||||
)
|
||||
fun condJump(condition: StackValue): CondJump {
|
||||
return CondJump(if (condition is BranchedValue) {
|
||||
condition
|
||||
}
|
||||
else {
|
||||
BranchedValue(condition, null, Type.BOOLEAN_TYPE, IFEQ)
|
||||
}, IFEQ)
|
||||
}
|
||||
|
||||
fun cmp(opToken: IElementType, operandType: Type, left: StackValue, right: StackValue): StackValue =
|
||||
if (operandType.sort == Type.OBJECT)
|
||||
@@ -194,7 +203,7 @@ class CondJump(val condition: BranchedValue, op: Int) : BranchedValue(condition,
|
||||
}
|
||||
|
||||
class NumberCompare(
|
||||
private val opToken: IElementType,
|
||||
val opToken: IElementType,
|
||||
operandType: Type,
|
||||
left: StackValue,
|
||||
right: StackValue
|
||||
@@ -204,15 +213,17 @@ class NumberCompare(
|
||||
patchOpcode(opcode, v, opToken, operandType)
|
||||
|
||||
companion object {
|
||||
fun getNumberCompareOpcode(opToken: IElementType): Int = when (opToken) {
|
||||
KtTokens.EQEQ, KtTokens.EQEQEQ -> IFNE
|
||||
KtTokens.EXCLEQ, KtTokens.EXCLEQEQEQ -> IFEQ
|
||||
KtTokens.GT -> IFLE
|
||||
KtTokens.GTEQ -> IFLT
|
||||
KtTokens.LT -> IFGE
|
||||
KtTokens.LTEQ -> IFGT
|
||||
else -> {
|
||||
throw UnsupportedOperationException("Don't know how to generate this condJump: " + opToken)
|
||||
fun getNumberCompareOpcode(opToken: IElementType): Int {
|
||||
return when (opToken) {
|
||||
KtTokens.EQEQ, KtTokens.EQEQEQ -> IFNE
|
||||
KtTokens.EXCLEQ, KtTokens.EXCLEQEQEQ -> IFEQ
|
||||
KtTokens.GT -> IFLE
|
||||
KtTokens.GTEQ -> IFLT
|
||||
KtTokens.LT -> IFGE
|
||||
KtTokens.LTEQ -> IFGT
|
||||
else -> {
|
||||
throw UnsupportedOperationException("Don't know how to generate this condJump: " + opToken)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,11 +258,100 @@ class ObjectCompare(
|
||||
) : BranchedValue(left, right, operandType, ObjectCompare.getObjectCompareOpcode(opToken)) {
|
||||
|
||||
companion object {
|
||||
fun getObjectCompareOpcode(opToken: IElementType): Int = when (opToken) {
|
||||
KtTokens.EQEQEQ -> IF_ACMPNE
|
||||
KtTokens.EXCLEQEQEQ -> IF_ACMPEQ
|
||||
else -> throw UnsupportedOperationException("don't know how to generate this condjump")
|
||||
fun getObjectCompareOpcode(opToken: IElementType): Int {
|
||||
return when (opToken) {
|
||||
KtTokens.EQEQEQ -> IF_ACMPNE
|
||||
KtTokens.EXCLEQEQEQ -> IF_ACMPEQ
|
||||
else -> throw UnsupportedOperationException("don't know how to generate this condjump")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SafeCallFusedWithPrimitiveEqualityBase(
|
||||
val opToken: IElementType,
|
||||
operandType: Type,
|
||||
left: StackValue,
|
||||
right: StackValue
|
||||
) : BranchedValue(left, right, operandType, NumberCompare.getNumberCompareOpcode(opToken)) {
|
||||
private val trueIfEqual = opToken == KtTokens.EQEQ || opToken == KtTokens.EQEQEQ
|
||||
|
||||
protected abstract fun cleanupOnNullReceiver(v: InstructionAdapter)
|
||||
|
||||
override fun patchOpcode(opcode: Int, v: InstructionAdapter): Int =
|
||||
NumberCompare.patchOpcode(opcode, v, opToken, operandType)
|
||||
|
||||
override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
|
||||
val endLabel = Label()
|
||||
|
||||
arg1.put(operandType, v)
|
||||
arg2!!.put(operandType, v)
|
||||
v.visitJumpInsn(patchOpcode(if (jumpIfFalse) opcode else negatedOperations[opcode]!!, v), jumpLabel)
|
||||
v.goTo(endLabel)
|
||||
|
||||
cleanupOnNullReceiver(v)
|
||||
if (jumpIfFalse == trueIfEqual) {
|
||||
v.goTo(jumpLabel)
|
||||
}
|
||||
|
||||
v.mark(endLabel)
|
||||
}
|
||||
|
||||
override fun putSelector(type: Type, v: InstructionAdapter) {
|
||||
val falseLabel = Label()
|
||||
val endLabel = Label()
|
||||
|
||||
arg1.put(operandType, v)
|
||||
arg2!!.put(operandType, v)
|
||||
v.visitJumpInsn(patchOpcode(opcode, v), falseLabel)
|
||||
|
||||
if (!trueIfEqual) {
|
||||
val trueLabel = Label()
|
||||
v.goTo(trueLabel)
|
||||
cleanupOnNullReceiver(v)
|
||||
v.mark(trueLabel)
|
||||
}
|
||||
|
||||
v.iconst(1)
|
||||
v.goTo(endLabel)
|
||||
|
||||
if (trueIfEqual) {
|
||||
cleanupOnNullReceiver(v)
|
||||
}
|
||||
|
||||
v.mark(falseLabel)
|
||||
v.iconst(0)
|
||||
|
||||
v.mark(endLabel)
|
||||
coerceTo(type, v)
|
||||
}
|
||||
}
|
||||
|
||||
class SafeCallToPrimitiveEquality(
|
||||
opToken: IElementType,
|
||||
operandType: Type,
|
||||
left: StackValue,
|
||||
right: StackValue,
|
||||
val safeReceiverType: Type,
|
||||
val safeReceiverIsNull: Label
|
||||
) : SafeCallFusedWithPrimitiveEqualityBase(opToken, operandType, left, right) {
|
||||
override fun cleanupOnNullReceiver(v: InstructionAdapter) {
|
||||
v.mark(safeReceiverIsNull)
|
||||
AsmUtil.pop(v, safeReceiverType)
|
||||
}
|
||||
}
|
||||
|
||||
class PrimitiveToSafeCallEquality(
|
||||
opToken: IElementType,
|
||||
operandType: Type,
|
||||
left: StackValue,
|
||||
right: StackValue,
|
||||
val safeReceiverType: Type,
|
||||
val safeReceiverIsNull: Label
|
||||
) : SafeCallFusedWithPrimitiveEqualityBase(opToken, operandType, left, right) {
|
||||
override fun cleanupOnNullReceiver(v: InstructionAdapter) {
|
||||
v.mark(safeReceiverIsNull)
|
||||
AsmUtil.pop(v, safeReceiverType)
|
||||
AsmUtil.pop(v, arg1.type)
|
||||
}
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.JavaClassProperty;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
public class CallReceiver extends StackValue {
|
||||
private final StackValue dispatchReceiver;
|
||||
private final StackValue extensionReceiver;
|
||||
private final Type secondReceiverType;
|
||||
|
||||
private CallReceiver(
|
||||
@NotNull StackValue dispatchReceiver,
|
||||
@NotNull StackValue extensionReceiver,
|
||||
@NotNull Type type,
|
||||
@Nullable Type secondReceiverType
|
||||
) {
|
||||
super(type, dispatchReceiver.canHaveSideEffects() || extensionReceiver.canHaveSideEffects());
|
||||
this.dispatchReceiver = dispatchReceiver;
|
||||
this.extensionReceiver = extensionReceiver;
|
||||
this.secondReceiverType = secondReceiverType;
|
||||
}
|
||||
|
||||
public StackValue withoutReceiverArgument() {
|
||||
return new CallReceiver(dispatchReceiver, none(), type, secondReceiverType);
|
||||
}
|
||||
|
||||
public static StackValue generateCallReceiver(
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@NotNull ExpressionCodegen codegen,
|
||||
@Nullable Callable callableMethod,
|
||||
@Nullable ReceiverParameterDescriptor dispatchReceiverParameter,
|
||||
@NotNull StackValue dispatchReceiver,
|
||||
@Nullable ReceiverParameterDescriptor extensionReceiverParameter,
|
||||
@NotNull StackValue extensionReceiver
|
||||
) {
|
||||
KotlinTypeMapper typeMapper = codegen.typeMapper;
|
||||
GenerationState state = codegen.getState();
|
||||
|
||||
Type type;
|
||||
Type secondReceiverType = null;
|
||||
if (extensionReceiverParameter != null) {
|
||||
type = calcExtensionReceiverType(resolvedCall, extensionReceiverParameter, typeMapper, callableMethod, state);
|
||||
if (dispatchReceiverParameter != null) {
|
||||
secondReceiverType = calcDispatchReceiverType(resolvedCall, dispatchReceiverParameter, typeMapper, callableMethod);
|
||||
}
|
||||
}
|
||||
else if (dispatchReceiverParameter != null) {
|
||||
type = calcDispatchReceiverType(resolvedCall, dispatchReceiverParameter, typeMapper, callableMethod);
|
||||
}
|
||||
else if (isLocalFunCall(callableMethod)) {
|
||||
type = callableMethod.getGenerateCalleeType();
|
||||
}
|
||||
else {
|
||||
type = Type.VOID_TYPE;
|
||||
}
|
||||
|
||||
assert type != null : "Could not map receiver type for " + resolvedCall;
|
||||
|
||||
return new CallReceiver(dispatchReceiver, extensionReceiver, type, secondReceiverType);
|
||||
}
|
||||
|
||||
private static Type calcDispatchReceiverType(
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@Nullable ReceiverParameterDescriptor dispatchReceiver,
|
||||
@NotNull KotlinTypeMapper typeMapper,
|
||||
@Nullable Callable callableMethod
|
||||
) {
|
||||
if (dispatchReceiver == null) return null;
|
||||
|
||||
CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
|
||||
|
||||
if (CodegenUtilKt.isJvmStaticInObjectOrClass(descriptor)) {
|
||||
return Type.VOID_TYPE;
|
||||
}
|
||||
|
||||
if (callableMethod != null) {
|
||||
return callableMethod.getDispatchReceiverType();
|
||||
}
|
||||
|
||||
// Extract the receiver from the resolved call, workarounding the fact that ResolvedCall#dispatchReceiver doesn't have
|
||||
// all the needed information, for example there's no way to find out whether or not a smart cast was applied to the receiver.
|
||||
DeclarationDescriptor container = descriptor.getContainingDeclaration();
|
||||
if (container instanceof ClassDescriptor) {
|
||||
return typeMapper.mapClass((ClassDescriptor) container);
|
||||
}
|
||||
|
||||
return typeMapper.mapType(dispatchReceiver);
|
||||
}
|
||||
|
||||
private static Type calcExtensionReceiverType(
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@Nullable ReceiverParameterDescriptor extensionReceiver,
|
||||
@NotNull KotlinTypeMapper typeMapper,
|
||||
@Nullable Callable callableMethod,
|
||||
@NotNull GenerationState state
|
||||
) {
|
||||
if (extensionReceiver == null) return null;
|
||||
|
||||
CallableDescriptor descriptor = resolvedCall.getCandidateDescriptor();
|
||||
|
||||
if (descriptor instanceof PropertyDescriptor &&
|
||||
// hackaround: boxing changes behaviour of T.javaClass intrinsic
|
||||
state.getIntrinsics().getIntrinsic((PropertyDescriptor) descriptor) != JavaClassProperty.INSTANCE
|
||||
) {
|
||||
ReceiverParameterDescriptor receiverCandidate = descriptor.getExtensionReceiverParameter();
|
||||
assert receiverCandidate != null;
|
||||
return typeMapper.mapType(receiverCandidate.getType());
|
||||
}
|
||||
|
||||
return callableMethod != null ? callableMethod.getExtensionReceiverType() : typeMapper.mapType(extensionReceiver.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
|
||||
StackValue currentExtensionReceiver = extensionReceiver;
|
||||
boolean hasExtensionReceiver = extensionReceiver != none();
|
||||
if (extensionReceiver instanceof SafeCall) {
|
||||
currentExtensionReceiver.put(currentExtensionReceiver.type, v);
|
||||
currentExtensionReceiver = StackValue.onStack(currentExtensionReceiver.type);
|
||||
}
|
||||
|
||||
Type dispatchReceiverType = secondReceiverType != null ? secondReceiverType :
|
||||
hasExtensionReceiver ? dispatchReceiver.type :
|
||||
type;
|
||||
dispatchReceiver.put(dispatchReceiverType, v);
|
||||
|
||||
currentExtensionReceiver
|
||||
.moveToTopOfStack(hasExtensionReceiver ? type : currentExtensionReceiver.type, v, dispatchReceiverType.getSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dup(@NotNull InstructionAdapter v, boolean withReceiver) {
|
||||
AsmUtil.dup(v, extensionReceiver.type, dispatchReceiver.type);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StackValue getDispatchReceiver() {
|
||||
return dispatchReceiver;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StackValue getExtensionReceiver() {
|
||||
return extensionReceiver;
|
||||
}
|
||||
}
|
||||
@@ -192,6 +192,6 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
|
||||
@Nullable
|
||||
@Override
|
||||
protected ClassDescriptor classForInnerClassRecord() {
|
||||
return DescriptorUtils.isTopLevelDeclaration(descriptor) ? null : descriptor;
|
||||
return InnerClassConsumer.Companion.classForInnerClassRecord(descriptor, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,12 +39,11 @@ import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenForLambda;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.ResolvedCallWithRealDescriptor;
|
||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
|
||||
import org.jetbrains.kotlin.codegen.forLoop.AbstractForLoopGenerator;
|
||||
import org.jetbrains.kotlin.codegen.forLoop.ForLoopGeneratorsKt;
|
||||
import org.jetbrains.kotlin.codegen.inline.*;
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.*;
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnsKt;
|
||||
import org.jetbrains.kotlin.codegen.range.RangeValue;
|
||||
import org.jetbrains.kotlin.codegen.range.RangeValuesKt;
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.ForLoopGenerator;
|
||||
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
|
||||
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
@@ -600,10 +599,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
private void generateFor(@NotNull KtForExpression forExpression) {
|
||||
KtExpression range = forExpression.getLoopRange();
|
||||
assert range != null : "No loop range in for expression";
|
||||
RangeValue rangeValue = RangeValuesKt.createRangeValueForExpression(this, range);
|
||||
generateForLoop(rangeValue.createForLoopGenerator(this, forExpression));
|
||||
generateForLoop(ForLoopGeneratorsKt.getForLoopGenerator(this, forExpression));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -627,7 +623,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
return context.getContextKind();
|
||||
}
|
||||
|
||||
private void generateForLoop(ForLoopGenerator generator) {
|
||||
private void generateForLoop(AbstractForLoopGenerator generator) {
|
||||
Label loopExit = new Label();
|
||||
Label loopEntry = new Label();
|
||||
Label continueLabel = new Label();
|
||||
@@ -2282,12 +2278,12 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
// But the problem is that we should leave the receiver itself on the stack, so we store it in a temporary variable.
|
||||
if (isSuspendCall && isSafeCallOrOnStack) {
|
||||
boolean bothReceivers =
|
||||
receiver instanceof CallReceiver
|
||||
&& ((CallReceiver) receiver).getDispatchReceiver().type.getSort() != Type.VOID
|
||||
&& ((CallReceiver) receiver).getExtensionReceiver().type.getSort() != Type.VOID;
|
||||
receiver instanceof StackValue.CallReceiver
|
||||
&& ((StackValue.CallReceiver) receiver).getDispatchReceiver().type.getSort() != Type.VOID
|
||||
&& ((StackValue.CallReceiver) receiver).getExtensionReceiver().type.getSort() != Type.VOID;
|
||||
Type firstReceiverType =
|
||||
bothReceivers
|
||||
? ((CallReceiver) receiver).getDispatchReceiver().type
|
||||
? ((StackValue.CallReceiver) receiver).getDispatchReceiver().type
|
||||
: receiver.type;
|
||||
|
||||
Type secondReceiverType = bothReceivers ? receiver.type : null;
|
||||
@@ -2855,9 +2851,76 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
private StackValue generateIn(StackValue leftValue, KtExpression rangeExpression, KtSimpleNameExpression operationReference) {
|
||||
KtExpression deparenthesized = KtPsiUtil.deparenthesize(rangeExpression);
|
||||
|
||||
assert deparenthesized != null : "For with empty range expression";
|
||||
RangeValue rangeValue = RangeValuesKt.createRangeValueForExpression(this, deparenthesized);
|
||||
return rangeValue.createInExpressionGenerator(this, operationReference).generate(leftValue);
|
||||
boolean isInverted = operationReference.getReferencedNameElementType() == KtTokens.NOT_IN;
|
||||
return StackValue.operation(Type.BOOLEAN_TYPE, v -> {
|
||||
if (RangeCodegenUtil.isPrimitiveRangeSpecializationOfType(leftValue.type, deparenthesized, bindingContext) ||
|
||||
RangeCodegenUtil.isPrimitiveRangeToExtension(operationReference, bindingContext)) {
|
||||
generateInPrimitiveRange(leftValue, (KtBinaryExpression) deparenthesized, isInverted);
|
||||
}
|
||||
else {
|
||||
ResolvedCall<? extends CallableDescriptor> resolvedCall = CallUtilKt
|
||||
.getResolvedCallWithAssert(operationReference, bindingContext);
|
||||
StackValue result = invokeFunction(resolvedCall.getCall(), resolvedCall, StackValue.none());
|
||||
result.put(result.type, v);
|
||||
if (isInverted) {
|
||||
genInvertBoolean(v);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Translates x in a..b to a <= x && x <= b
|
||||
* and x !in a..b to a > x || x > b for any primitive type
|
||||
*/
|
||||
private void generateInPrimitiveRange(StackValue argument, KtBinaryExpression rangeExpression, boolean isInverted) {
|
||||
Type rangeType = argument.type;
|
||||
int localVarIndex = myFrameMap.enterTemp(rangeType);
|
||||
// Load left bound
|
||||
gen(rangeExpression.getLeft(), rangeType);
|
||||
// Load x into local variable to avoid StackValue#put side-effects
|
||||
argument.put(rangeType, v);
|
||||
v.store(localVarIndex, rangeType);
|
||||
v.load(localVarIndex, rangeType);
|
||||
|
||||
// If (x < left) goto L1
|
||||
Label l1 = new Label();
|
||||
emitGreaterThan(rangeType, l1);
|
||||
|
||||
// If (x > right) goto L1
|
||||
v.load(localVarIndex, rangeType);
|
||||
gen(rangeExpression.getRight(), rangeType);
|
||||
emitGreaterThan(rangeType, l1);
|
||||
|
||||
Label l2 = new Label();
|
||||
v.iconst(isInverted ? 0 : 1);
|
||||
v.goTo(l2);
|
||||
|
||||
v.mark(l1);
|
||||
v.iconst(isInverted ? 1 : 0);
|
||||
v.mark(l2);
|
||||
myFrameMap.leaveTemp(rangeType);
|
||||
}
|
||||
|
||||
private void emitGreaterThan(Type type, Label label) {
|
||||
if (AsmUtil.isIntPrimitive(type)) {
|
||||
v.ificmpgt(label);
|
||||
}
|
||||
else if (type == Type.LONG_TYPE) {
|
||||
v.lcmp();
|
||||
v.ifgt(label);
|
||||
}
|
||||
// '>' != 'compareTo' for NaN and +/- 0.0
|
||||
else if (type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE) {
|
||||
v.cmpg(type);
|
||||
v.ifgt(label);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Unexpected type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
private StackValue generateBooleanAnd(KtBinaryExpression expression) {
|
||||
@@ -2888,27 +2951,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
return genCmpWithZero(left, opToken);
|
||||
}
|
||||
|
||||
if (left instanceof KtSafeQualifiedExpression && isPrimitive(rightType)) {
|
||||
if (left instanceof KtSafeQualifiedExpression
|
||||
&& isSelectorPureNonNullType((KtSafeQualifiedExpression) left) && isPrimitive(rightType)) {
|
||||
return genCmpSafeCallToPrimitive((KtSafeQualifiedExpression) left, right, rightType, opToken);
|
||||
}
|
||||
if (isPrimitive(leftType) && right instanceof KtSafeQualifiedExpression) {
|
||||
if (isPrimitive(leftType) && right instanceof KtSafeQualifiedExpression && isSelectorPureNonNullType(((KtSafeQualifiedExpression) right))) {
|
||||
return genCmpPrimitiveToSafeCall(left, leftType, (KtSafeQualifiedExpression) right, opToken);
|
||||
}
|
||||
|
||||
if (BoxedToPrimitiveEquality.isApplicable(opToken, leftType, rightType)) {
|
||||
return BoxedToPrimitiveEquality.create(opToken, genLazy(left, leftType), leftType, genLazy(right, rightType), rightType,
|
||||
myFrameMap);
|
||||
}
|
||||
|
||||
if (PrimitiveToBoxedEquality.isApplicable(opToken, leftType, rightType)) {
|
||||
return PrimitiveToBoxedEquality.create(opToken, genLazy(left, leftType), leftType, genLazy(right, rightType), rightType);
|
||||
}
|
||||
|
||||
if (PrimitiveToObjectEquality.isApplicable(opToken, leftType, rightType)) {
|
||||
return PrimitiveToObjectEquality.create(opToken, genLazy(left, leftType), leftType, genLazy(right, rightType), rightType);
|
||||
}
|
||||
|
||||
|
||||
if (isPrimitive(leftType) != isPrimitive(rightType)) {
|
||||
leftType = boxType(leftType);
|
||||
rightType = boxType(rightType);
|
||||
@@ -2923,6 +2973,15 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
return genEqualsForExpressionsPreferIEEE754Arithmetic(left, right, opToken, leftType, rightType, null);
|
||||
}
|
||||
|
||||
private boolean isSelectorPureNonNullType(@NotNull KtSafeQualifiedExpression safeExpression) {
|
||||
KtExpression expression = safeExpression.getSelectorExpression();
|
||||
if (expression == null) return false;
|
||||
ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCall(expression, bindingContext);
|
||||
if (resolvedCall == null) return false;
|
||||
KotlinType returnType = resolvedCall.getResultingDescriptor().getReturnType();
|
||||
return returnType != null && !TypeUtils.isNullableType(returnType);
|
||||
}
|
||||
|
||||
private StackValue genCmpPrimitiveToSafeCall(
|
||||
@NotNull KtExpression left,
|
||||
@NotNull Type leftType,
|
||||
|
||||
@@ -595,8 +595,31 @@ public class FunctionCodegen {
|
||||
@NotNull KotlinTypeMapper typeMapper,
|
||||
int shiftForDestructuringVariables
|
||||
) {
|
||||
generateLocalVariablesForParameters(mv, jvmMethodSignature, thisType, methodBegin, methodEnd,
|
||||
functionDescriptor.getValueParameters(),
|
||||
if (functionDescriptor.isSuspend()) {
|
||||
FunctionDescriptor unwrapped = CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(
|
||||
functionDescriptor
|
||||
);
|
||||
|
||||
if (unwrapped != functionDescriptor) {
|
||||
generateLocalVariableTable(
|
||||
mv,
|
||||
new JvmMethodSignature(
|
||||
jvmMethodSignature.getAsmMethod(),
|
||||
jvmMethodSignature.getValueParameters().subList(
|
||||
0,
|
||||
jvmMethodSignature.getValueParameters().size() - 1
|
||||
)
|
||||
),
|
||||
unwrapped,
|
||||
thisType, methodBegin, methodEnd, ownerKind, typeMapper, shiftForDestructuringVariables
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
generateLocalVariablesForParameters(mv,
|
||||
jvmMethodSignature,
|
||||
thisType, methodBegin, methodEnd, functionDescriptor.getValueParameters(),
|
||||
AsmUtil.isStaticMethod(ownerKind, functionDescriptor), typeMapper, shiftForDestructuringVariables
|
||||
);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
|
||||
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
@@ -65,7 +64,10 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
import org.jetbrains.org.objectweb.asm.FieldVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||
|
||||
@@ -346,12 +348,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateSyntheticPartsBeforeBody() {
|
||||
protected void generateSyntheticParts() {
|
||||
generatePropertyMetadataArrayFieldIfNeeded(classAsmType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateSyntheticPartsAfterBody() {
|
||||
generateFieldForSingleton();
|
||||
|
||||
generateCompanionObjectBackingFieldCopies();
|
||||
@@ -836,21 +835,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
@Nullable KtObjectDeclaration companionObject = CollectionsKt.firstOrNull(myClass.getCompanionObjects());
|
||||
|
||||
int properFieldVisibilityFlag = getVisibilityAccessFlag(companionObjectDescriptor);
|
||||
boolean fieldShouldBeDeprecated =
|
||||
state.getLanguageVersionSettings().supportsFeature(LanguageFeature.DeprecatedFieldForInvisibleCompanionObject) &&
|
||||
(properFieldVisibilityFlag & (ACC_PRIVATE | ACC_PROTECTED)) != 0;
|
||||
// TODO generate field with proper visibility in language version 1.3
|
||||
int fieldAccessFlags = ACC_PUBLIC | ACC_STATIC | ACC_FINAL;
|
||||
if (fieldShouldBeDeprecated) {
|
||||
fieldAccessFlags |= ACC_DEPRECATED;
|
||||
}
|
||||
StackValue.Field field = StackValue.singleton(companionObjectDescriptor, typeMapper);
|
||||
FieldVisitor fv = v.newField(JvmDeclarationOriginKt.OtherOrigin(companionObject == null ? myClass.getPsiOrParent() : companionObject),
|
||||
fieldAccessFlags, field.name, field.type.getDescriptor(), null, null);
|
||||
if (fieldShouldBeDeprecated) {
|
||||
AnnotationCodegen.forField(fv, this, typeMapper).visitAnnotation("Ljava/lang/Deprecated;", true).visitEnd();
|
||||
}
|
||||
v.newField(JvmDeclarationOriginKt.OtherOrigin(companionObject == null ? myClass.getPsiOrParent() : companionObject),
|
||||
ACC_PUBLIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null);
|
||||
}
|
||||
|
||||
private void generateCompanionObjectBackingFieldCopies() {
|
||||
|
||||
@@ -17,7 +17,35 @@
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import java.util.*
|
||||
|
||||
interface InnerClassConsumer {
|
||||
fun addInnerClassInfoFromAnnotation(classDescriptor: ClassDescriptor)
|
||||
|
||||
companion object {
|
||||
|
||||
fun classForInnerClassRecord(descriptor: ClassDescriptor, defaultImpls: Boolean): ClassDescriptor? {
|
||||
if (defaultImpls) {
|
||||
if (DescriptorUtils.isLocal(descriptor)) return null
|
||||
val classDescriptorImpl = ClassDescriptorImpl(
|
||||
descriptor, Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME),
|
||||
Modality.FINAL, ClassKind.CLASS, Collections.emptyList(), SourceElement.NO_SOURCE,
|
||||
/* isExternal = */ false)
|
||||
|
||||
classDescriptorImpl.initialize(MemberScope.Empty, emptySet(), null)
|
||||
return classDescriptorImpl
|
||||
}
|
||||
else {
|
||||
return if (DescriptorUtils.isTopLevelDeclaration(descriptor)) null else descriptor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,20 +22,14 @@ import org.jetbrains.kotlin.backend.common.bridges.firstSuperMethodFromKotlin
|
||||
import org.jetbrains.kotlin.codegen.context.ClassContext
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtPureClassOrObject
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||
import java.util.*
|
||||
|
||||
class InterfaceImplBodyCodegen(
|
||||
aClass: KtPureClassOrObject,
|
||||
@@ -47,12 +41,14 @@ class InterfaceImplBodyCodegen(
|
||||
private var isAnythingGenerated: Boolean = false
|
||||
get() = (v as InterfaceImplClassBuilder).isAnythingGenerated
|
||||
|
||||
private val defaultImplType = typeMapper.mapDefaultImpls(descriptor)
|
||||
|
||||
override fun generateDeclaration() {
|
||||
val codegenFlags = ACC_PUBLIC or ACC_FINAL or ACC_SUPER
|
||||
val flags = if (state.classBuilderMode == ClassBuilderMode.LIGHT_CLASSES) codegenFlags or ACC_STATIC else codegenFlags
|
||||
v.defineClass(
|
||||
myClass.psiOrParent, state.classFileVersion, flags,
|
||||
typeMapper.mapDefaultImpls(descriptor).internalName,
|
||||
defaultImplType.internalName,
|
||||
null, "java/lang/Object", ArrayUtil.EMPTY_STRING_ARRAY
|
||||
)
|
||||
v.visitSource(myClass.containingKtFile.name, null)
|
||||
@@ -60,17 +56,10 @@ class InterfaceImplBodyCodegen(
|
||||
|
||||
override fun classForInnerClassRecord(): ClassDescriptor? {
|
||||
if (!isAnythingGenerated) return null
|
||||
if (DescriptorUtils.isLocal(descriptor)) return null
|
||||
val classDescriptorImpl = ClassDescriptorImpl(
|
||||
descriptor, Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME),
|
||||
Modality.FINAL, ClassKind.CLASS, Collections.emptyList(), SourceElement.NO_SOURCE,
|
||||
/* isExternal = */ false)
|
||||
|
||||
classDescriptorImpl.initialize(MemberScope.Empty, emptySet(), null)
|
||||
return classDescriptorImpl
|
||||
return InnerClassConsumer.classForInnerClassRecord(descriptor, true)
|
||||
}
|
||||
|
||||
override fun generateSyntheticPartsAfterBody() {
|
||||
override fun generateSyntheticParts() {
|
||||
for (memberDescriptor in descriptor.defaultType.memberScope.getContributedDescriptors()) {
|
||||
if (memberDescriptor !is CallableMemberDescriptor) continue
|
||||
|
||||
@@ -161,7 +150,7 @@ class InterfaceImplBodyCodegen(
|
||||
override fun done() {
|
||||
super.done()
|
||||
if (!isAnythingGenerated) {
|
||||
state.factory.removeClasses(setOf(typeMapper.mapDefaultImpls(descriptor).internalName))
|
||||
state.factory.removeClasses(setOf(defaultImplType.internalName))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,4 +179,8 @@ class InterfaceImplBodyCodegen(
|
||||
return super.newMethod(origin, access, name, desc, signature, exceptions)
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateSyntheticPartsBeforeBody() {
|
||||
generatePropertyMetadataArrayFieldIfNeeded(defaultImplType)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,8 @@ class JvmStaticInCompanionObjectGenerator(
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
false
|
||||
)
|
||||
return copies[descriptor]!!
|
||||
val staticFunctionDescriptor = copies[descriptor]!!
|
||||
return staticFunctionDescriptor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||
import org.jetbrains.kotlin.fileClasses.FileClasses;
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider;
|
||||
@@ -50,7 +49,6 @@ import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptor;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
@@ -147,7 +145,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
generateBody();
|
||||
|
||||
if (shouldGenerateSyntheticParts) {
|
||||
generateSyntheticPartsAfterBody();
|
||||
generateSyntheticParts();
|
||||
}
|
||||
|
||||
if (state.getClassBuilderMode().generateMetadata) {
|
||||
@@ -157,14 +155,14 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
done();
|
||||
}
|
||||
|
||||
protected abstract void generateDeclaration();
|
||||
|
||||
protected void generateSyntheticPartsBeforeBody() {
|
||||
}
|
||||
|
||||
protected abstract void generateDeclaration();
|
||||
|
||||
protected abstract void generateBody();
|
||||
|
||||
protected void generateSyntheticPartsAfterBody() {
|
||||
protected void generateSyntheticParts() {
|
||||
}
|
||||
|
||||
protected abstract void generateKotlinMetadataAnnotation();
|
||||
@@ -344,12 +342,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
parentCodegen.innerClasses.add(classDescriptor);
|
||||
}
|
||||
|
||||
for (MemberCodegen<?> codegen = this; codegen != null; codegen = codegen.getParentCodegen()) {
|
||||
ClassDescriptor outerClass = codegen.classForInnerClassRecord();
|
||||
if (outerClass != null) {
|
||||
innerClasses.add(outerClass);
|
||||
}
|
||||
}
|
||||
addParentsToInnerClassesIfNeeded(innerClasses);
|
||||
}
|
||||
|
||||
for (ClassDescriptor innerClass : innerClasses) {
|
||||
@@ -357,6 +350,18 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
}
|
||||
}
|
||||
|
||||
protected void addParentsToInnerClassesIfNeeded(@NotNull Collection<ClassDescriptor> innerClasses) {
|
||||
ClassDescriptor outerClass = classForInnerClassRecord();
|
||||
if (outerClass != null) {
|
||||
innerClasses.add(outerClass);
|
||||
}
|
||||
|
||||
MemberCodegen<?> parentCodegen = getParentCodegen();
|
||||
if (parentCodegen != null) {
|
||||
parentCodegen.addParentsToInnerClassesIfNeeded(innerClasses);
|
||||
}
|
||||
}
|
||||
|
||||
// It's necessary for proper recovering of classId by plain string JVM descriptor when loading annotations
|
||||
// See FileBasedKotlinClass.convertAnnotationVisitor
|
||||
@Override
|
||||
|
||||
@@ -189,7 +189,7 @@ class MultifileClassPartCodegen(
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateSyntheticPartsAfterBody() {
|
||||
override fun generateSyntheticParts() {
|
||||
generateSyntheticAccessors()
|
||||
}
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ public class PackagePartCodegen extends MemberCodegen<KtFile> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateSyntheticPartsAfterBody() {
|
||||
protected void generateSyntheticParts() {
|
||||
generateSyntheticAccessors();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.RANGES_PACKAGE_FQ_NAME;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitiveNumberClassDescriptor;
|
||||
|
||||
public class RangeCodegenUtil {
|
||||
private static final ImmutableMap<FqName, PrimitiveType> RANGE_TO_ELEMENT_TYPE;
|
||||
private static final ImmutableMap<FqName, PrimitiveType> PROGRESSION_TO_ELEMENT_TYPE;
|
||||
|
||||
@NotNull
|
||||
public static List<PrimitiveType> supportedRangeTypes() {
|
||||
return Arrays.asList(PrimitiveType.CHAR, PrimitiveType.INT, PrimitiveType.LONG);
|
||||
}
|
||||
|
||||
static {
|
||||
ImmutableMap.Builder<FqName, PrimitiveType> rangeBuilder = ImmutableMap.builder();
|
||||
ImmutableMap.Builder<FqName, PrimitiveType> progressionBuilder = ImmutableMap.builder();
|
||||
for (PrimitiveType primitiveType : supportedRangeTypes()) {
|
||||
FqName rangeClassFqName = RANGES_PACKAGE_FQ_NAME.child(Name.identifier(primitiveType.getTypeName() + "Range"));
|
||||
FqName progressionClassFqName = RANGES_PACKAGE_FQ_NAME.child(Name.identifier(primitiveType.getTypeName() + "Progression"));
|
||||
rangeBuilder.put(rangeClassFqName, primitiveType);
|
||||
progressionBuilder.put(progressionClassFqName, primitiveType);
|
||||
}
|
||||
RANGE_TO_ELEMENT_TYPE = rangeBuilder.build();
|
||||
PROGRESSION_TO_ELEMENT_TYPE = progressionBuilder.build();
|
||||
}
|
||||
|
||||
private RangeCodegenUtil() {}
|
||||
|
||||
public static boolean isRange(KotlinType rangeType) {
|
||||
return !rangeType.isMarkedNullable() && getPrimitiveRangeElementType(rangeType) != null;
|
||||
}
|
||||
|
||||
public static boolean isProgression(KotlinType rangeType) {
|
||||
return !rangeType.isMarkedNullable() && getPrimitiveProgressionElementType(rangeType) != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PrimitiveType getPrimitiveRangeElementType(KotlinType rangeType) {
|
||||
return getPrimitiveRangeOrProgressionElementType(rangeType, RANGE_TO_ELEMENT_TYPE);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PrimitiveType getPrimitiveProgressionElementType(KotlinType rangeType) {
|
||||
return getPrimitiveRangeOrProgressionElementType(rangeType, PROGRESSION_TO_ELEMENT_TYPE);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PrimitiveType getPrimitiveRangeOrProgressionElementType(
|
||||
@NotNull KotlinType rangeOrProgression,
|
||||
@NotNull ImmutableMap<FqName, PrimitiveType> map
|
||||
) {
|
||||
ClassifierDescriptor declarationDescriptor = rangeOrProgression.getConstructor().getDeclarationDescriptor();
|
||||
if (declarationDescriptor == null) return null;
|
||||
FqNameUnsafe fqName = DescriptorUtils.getFqName(declarationDescriptor);
|
||||
if (!fqName.isSafe()) return null;
|
||||
return map.get(fqName.toSafe());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PrimitiveType getPrimitiveRangeOrProgressionElementType(@NotNull FqName rangeOrProgressionName) {
|
||||
PrimitiveType result = RANGE_TO_ELEMENT_TYPE.get(rangeOrProgressionName);
|
||||
return result != null ? result : PROGRESSION_TO_ELEMENT_TYPE.get(rangeOrProgressionName);
|
||||
}
|
||||
|
||||
public static boolean isRangeOrProgression(@NotNull FqName className) {
|
||||
return getPrimitiveRangeOrProgressionElementType(className) != null;
|
||||
}
|
||||
|
||||
public static boolean isPrimitiveNumberRangeTo(CallableDescriptor rangeTo) {
|
||||
if (!"rangeTo".equals(rangeTo.getName().asString())) return false;
|
||||
|
||||
if (!isPrimitiveNumberClassDescriptor(rangeTo.getContainingDeclaration())) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isPrimitiveRangeToExtension(@NotNull CallableDescriptor descriptor) {
|
||||
if (!isTopLevelInPackage(descriptor, "rangeTo", "kotlin.ranges")) return false;
|
||||
|
||||
ReceiverParameterDescriptor extensionReceiver = descriptor.getExtensionReceiverParameter();
|
||||
if (extensionReceiver == null) return false;
|
||||
|
||||
return KotlinBuiltIns.isPrimitiveType(extensionReceiver.getType());
|
||||
}
|
||||
|
||||
public static boolean isPrimitiveNumberDownTo(@NotNull CallableDescriptor descriptor) {
|
||||
if (!isTopLevelInPackage(descriptor, "downTo", "kotlin.ranges")) return false;
|
||||
|
||||
ReceiverParameterDescriptor extensionReceiver = descriptor.getExtensionReceiverParameter();
|
||||
if (extensionReceiver == null) return false;
|
||||
ClassifierDescriptor extensionReceiverClassifier = extensionReceiver.getType().getConstructor().getDeclarationDescriptor();
|
||||
if (!isPrimitiveNumberClassDescriptor(extensionReceiverClassifier)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isPrimitiveNumberUntil(@NotNull CallableDescriptor descriptor) {
|
||||
if (!isTopLevelInPackage(descriptor, "until", "kotlin.ranges")) return false;
|
||||
|
||||
ReceiverParameterDescriptor extensionReceiver = descriptor.getExtensionReceiverParameter();
|
||||
if (extensionReceiver == null) return false;
|
||||
ClassifierDescriptor extensionReceiverClassifier = extensionReceiver.getType().getConstructor().getDeclarationDescriptor();
|
||||
if (!isPrimitiveNumberClassDescriptor(extensionReceiverClassifier)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isArrayOrPrimitiveArrayIndices(@NotNull CallableDescriptor descriptor) {
|
||||
if (!isTopLevelInPackage(descriptor, "indices", "kotlin.collections")) return false;
|
||||
|
||||
ReceiverParameterDescriptor extensionReceiver = descriptor.getExtensionReceiverParameter();
|
||||
if (extensionReceiver == null) return false;
|
||||
KotlinType extensionReceiverType = extensionReceiver.getType();
|
||||
if (!KotlinBuiltIns.isArray(extensionReceiverType) && !KotlinBuiltIns.isPrimitiveArray(extensionReceiverType)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isCollectionIndices(@NotNull CallableDescriptor descriptor) {
|
||||
if (!isTopLevelInPackage(descriptor, "indices", "kotlin.collections")) return false;
|
||||
|
||||
ReceiverParameterDescriptor extensionReceiver = descriptor.getExtensionReceiverParameter();
|
||||
if (extensionReceiver == null) return false;
|
||||
KotlinType extensionReceiverType = extensionReceiver.getType();
|
||||
if (!KotlinBuiltIns.isCollectionOrNullableCollection(extensionReceiverType)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isCharSequenceIndices(@NotNull CallableDescriptor descriptor) {
|
||||
if (!isTopLevelInPackage(descriptor, "indices", "kotlin.text")) return false;
|
||||
|
||||
ReceiverParameterDescriptor extensionReceiver = descriptor.getExtensionReceiverParameter();
|
||||
if (extensionReceiver == null) return false;
|
||||
KotlinType extensionReceiverType = extensionReceiver.getType();
|
||||
if (!KotlinBuiltIns.isCharSequenceOrNullableCharSequence(extensionReceiverType)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isPrimitiveRangeToExtension(@NotNull KtSimpleNameExpression operationReference, @NotNull BindingContext bindingContext) {
|
||||
ResolvedCall<? extends CallableDescriptor> resolvedCall = CallUtilKt
|
||||
.getResolvedCallWithAssert(operationReference, bindingContext);
|
||||
ReceiverValue receiver = resolvedCall.getDispatchReceiver();
|
||||
|
||||
/*
|
||||
* Range is optimizable if
|
||||
* 'in' receiver is expression 'rangeTo' from stdlib package
|
||||
* and its argument has same primitive type as generic range parameter.
|
||||
* For non-matching primitive types (e.g. int in double range)
|
||||
* dispatch receiver will be null, because extension method will be called.
|
||||
*/
|
||||
if (!(receiver instanceof ExpressionReceiver)) return false;
|
||||
ExpressionReceiver e = (ExpressionReceiver) receiver;
|
||||
|
||||
ResolvedCall<? extends CallableDescriptor> resolvedReceiver =
|
||||
CallUtilKt.getResolvedCall(e.getExpression(), bindingContext);
|
||||
if (resolvedReceiver == null) return false;
|
||||
|
||||
return isPrimitiveRangeToExtension(resolvedReceiver.getResultingDescriptor());
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks whether for expression 'x in a..b' a..b is primitive integral range
|
||||
* with same type as x.
|
||||
*/
|
||||
public static boolean isPrimitiveRangeSpecializationOfType(
|
||||
@NotNull Type argumentType,
|
||||
@NotNull KtExpression rangeExpression,
|
||||
@NotNull BindingContext bindingContext
|
||||
) {
|
||||
if (rangeExpression instanceof KtBinaryExpression &&
|
||||
((KtBinaryExpression) rangeExpression).getOperationReference().getReferencedNameElementType() == KtTokens.RANGE) {
|
||||
KotlinType kotlinType = bindingContext.getType(rangeExpression);
|
||||
assert kotlinType != null;
|
||||
DeclarationDescriptor descriptor = kotlinType.getConstructor().getDeclarationDescriptor();
|
||||
if (descriptor != null) {
|
||||
FqNameUnsafe fqName = DescriptorUtils.getFqName(descriptor);
|
||||
if (fqName.equals(KotlinBuiltIns.FQ_NAMES.longRange)) {
|
||||
return argumentType == Type.LONG_TYPE;
|
||||
}
|
||||
if (fqName.equals(KotlinBuiltIns.FQ_NAMES.charRange) || fqName.equals(KotlinBuiltIns.FQ_NAMES.intRange)) {
|
||||
return AsmUtil.isIntPrimitive(argumentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isTopLevelInPackage(@NotNull CallableDescriptor descriptor, @NotNull String name, @NotNull String packageName) {
|
||||
if (!name.equals(descriptor.getName().asString())) return false;
|
||||
|
||||
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
|
||||
if (!(containingDeclaration instanceof PackageFragmentDescriptor)) return false;
|
||||
String packageFqName = ((PackageFragmentDescriptor) containingDeclaration).getFqName().asString();
|
||||
if (!packageName.equals(packageFqName)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,242 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.RANGES_PACKAGE_FQ_NAME
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitiveNumberClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
|
||||
val supportedRangeTypes = listOf(PrimitiveType.CHAR, PrimitiveType.INT, PrimitiveType.LONG)
|
||||
|
||||
private val RANGE_TO_ELEMENT_TYPE: Map<FqName, PrimitiveType> =
|
||||
supportedRangeTypes.associateBy {
|
||||
RANGES_PACKAGE_FQ_NAME.child(Name.identifier(it.typeName.toString() + "Range"))
|
||||
}
|
||||
|
||||
private val PROGRESSION_TO_ELEMENT_TYPE: Map<FqName, PrimitiveType> =
|
||||
supportedRangeTypes.associateBy {
|
||||
RANGES_PACKAGE_FQ_NAME.child(Name.identifier(it.typeName.toString() + "Progression"))
|
||||
}
|
||||
|
||||
fun isPrimitiveRange(rangeType: KotlinType) =
|
||||
!rangeType.isMarkedNullable && getPrimitiveRangeElementType(rangeType) != null
|
||||
|
||||
fun isPrimitiveProgression(rangeType: KotlinType) =
|
||||
!rangeType.isMarkedNullable && getPrimitiveProgressionElementType(rangeType) != null
|
||||
|
||||
fun getPrimitiveRangeElementType(rangeType: KotlinType): PrimitiveType? =
|
||||
getPrimitiveRangeOrProgressionElementType(rangeType, RANGE_TO_ELEMENT_TYPE)
|
||||
|
||||
private fun getPrimitiveProgressionElementType(rangeType: KotlinType) =
|
||||
getPrimitiveRangeOrProgressionElementType(rangeType, PROGRESSION_TO_ELEMENT_TYPE)
|
||||
|
||||
private fun getPrimitiveRangeOrProgressionElementType(
|
||||
rangeOrProgression: KotlinType,
|
||||
map: Map<FqName, PrimitiveType>
|
||||
): PrimitiveType? {
|
||||
val declarationDescriptor = rangeOrProgression.constructor.declarationDescriptor ?: return null
|
||||
val fqName = DescriptorUtils.getFqName(declarationDescriptor).takeIf { it.isSafe } ?: return null
|
||||
return map[fqName.toSafe()]
|
||||
}
|
||||
|
||||
fun getRangeOrProgressionElementType(rangeType: KotlinType): KotlinType? {
|
||||
val rangeTypeDescriptor = rangeType.constructor.declarationDescriptor ?: return null
|
||||
val builtIns = rangeTypeDescriptor.builtIns
|
||||
|
||||
return when {
|
||||
isTopLevelInPackage(rangeTypeDescriptor, "CharRange", "kotlin.ranges") -> builtIns.charType
|
||||
isTopLevelInPackage(rangeTypeDescriptor, "IntRange", "kotlin.ranges") -> builtIns.intType
|
||||
isTopLevelInPackage(rangeTypeDescriptor, "LongRange", "kotlin.ranges") -> builtIns.longType
|
||||
|
||||
isTopLevelInPackage(rangeTypeDescriptor, "CharProgression", "kotlin.ranges") -> builtIns.charType
|
||||
isTopLevelInPackage(rangeTypeDescriptor, "IntProgression", "kotlin.ranges") -> builtIns.intType
|
||||
isTopLevelInPackage(rangeTypeDescriptor, "LongProgression", "kotlin.ranges") -> builtIns.longType
|
||||
|
||||
isTopLevelInPackage(rangeTypeDescriptor, "ClosedFloatRange", "kotlin.ranges") -> builtIns.floatType
|
||||
isTopLevelInPackage(rangeTypeDescriptor, "ClosedDoubleRange", "kotlin.ranges") -> builtIns.doubleType
|
||||
|
||||
isTopLevelInPackage(rangeTypeDescriptor, "ClosedRange", "kotlin.ranges") -> rangeType.arguments.singleOrNull()?.type
|
||||
|
||||
isTopLevelInPackage(rangeTypeDescriptor, "ClosedFloatingPointRange", "kotlin.ranges") -> rangeType.arguments.singleOrNull()?.type
|
||||
|
||||
isTopLevelInPackage(rangeTypeDescriptor, "ComparableRange", "kotlin.ranges") -> rangeType.arguments.singleOrNull()?.type
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun getPrimitiveRangeOrProgressionElementType(rangeOrProgressionName: FqName): PrimitiveType? =
|
||||
RANGE_TO_ELEMENT_TYPE[rangeOrProgressionName] ?:
|
||||
PROGRESSION_TO_ELEMENT_TYPE[rangeOrProgressionName]
|
||||
|
||||
fun isRangeOrProgression(className: FqName) =
|
||||
getPrimitiveRangeOrProgressionElementType(className) != null
|
||||
|
||||
fun isPrimitiveNumberRangeTo(rangeTo: CallableDescriptor) =
|
||||
"rangeTo" == rangeTo.name.asString() && isPrimitiveNumberClassDescriptor(rangeTo.containingDeclaration) ||
|
||||
isPrimitiveRangeToExtension(rangeTo)
|
||||
|
||||
private fun isPrimitiveRangeToExtension(descriptor: CallableDescriptor): Boolean {
|
||||
if (!isTopLevelInPackage(descriptor, "rangeTo", "kotlin.ranges")) return false
|
||||
|
||||
val extensionReceiver = descriptor.extensionReceiverParameter ?: return false
|
||||
return KotlinBuiltIns.isPrimitiveType(extensionReceiver.type)
|
||||
}
|
||||
|
||||
fun isPrimitiveNumberDownTo(descriptor: CallableDescriptor): Boolean {
|
||||
if (!isTopLevelInPackage(descriptor, "downTo", "kotlin.ranges")) return false
|
||||
|
||||
val extensionReceiver = descriptor.extensionReceiverParameter ?: return false
|
||||
val extensionReceiverClassifier = extensionReceiver.type.constructor.declarationDescriptor
|
||||
return isPrimitiveNumberClassDescriptor(extensionReceiverClassifier)
|
||||
}
|
||||
|
||||
fun isPrimitiveNumberUntil(descriptor: CallableDescriptor): Boolean {
|
||||
if (!isTopLevelInPackage(descriptor, "until", "kotlin.ranges")) return false
|
||||
|
||||
val extensionReceiver = descriptor.extensionReceiverParameter ?: return false
|
||||
val extensionReceiverClassifier = extensionReceiver.type.constructor.declarationDescriptor
|
||||
return isPrimitiveNumberClassDescriptor(extensionReceiverClassifier)
|
||||
}
|
||||
|
||||
fun isArrayOrPrimitiveArrayIndices(descriptor: CallableDescriptor): Boolean {
|
||||
if (!isTopLevelInPackage(descriptor, "indices", "kotlin.collections")) return false
|
||||
|
||||
val extensionReceiver = descriptor.extensionReceiverParameter ?: return false
|
||||
val extensionReceiverType = extensionReceiver.type
|
||||
return KotlinBuiltIns.isArray(extensionReceiverType) || KotlinBuiltIns.isPrimitiveArray(extensionReceiverType)
|
||||
}
|
||||
|
||||
fun isCollectionIndices(descriptor: CallableDescriptor): Boolean {
|
||||
if (!isTopLevelInPackage(descriptor, "indices", "kotlin.collections")) return false
|
||||
|
||||
val extensionReceiver = descriptor.extensionReceiverParameter ?: return false
|
||||
val extensionReceiverType = extensionReceiver.type
|
||||
return KotlinBuiltIns.isCollectionOrNullableCollection(extensionReceiverType)
|
||||
}
|
||||
|
||||
fun isCharSequenceIndices(descriptor: CallableDescriptor): Boolean {
|
||||
if (!isTopLevelInPackage(descriptor, "indices", "kotlin.text")) return false
|
||||
|
||||
val extensionReceiver = descriptor.extensionReceiverParameter ?: return false
|
||||
val extensionReceiverType = extensionReceiver.type
|
||||
return KotlinBuiltIns.isCharSequenceOrNullableCharSequence(extensionReceiverType)
|
||||
}
|
||||
|
||||
fun isComparableRangeTo(descriptor: CallableDescriptor): Boolean {
|
||||
if (!isTopLevelInPackage(descriptor, "rangeTo", "kotlin.ranges")) return false
|
||||
|
||||
val extensionReceiver = descriptor.original.extensionReceiverParameter ?: return false
|
||||
val extensionReceiverTypeDescriptor = extensionReceiver.type.constructor.declarationDescriptor as? TypeParameterDescriptor ?: return false
|
||||
val upperBoundType = extensionReceiverTypeDescriptor.upperBounds.singleOrNull() ?: return false
|
||||
val upperBoundClassDescriptor = upperBoundType.constructor.declarationDescriptor as? ClassDescriptor ?: return false
|
||||
if (!isTopLevelInPackage(upperBoundClassDescriptor, "Comparable", "kotlin")) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun isClosedRangeContains(descriptor: CallableDescriptor): Boolean {
|
||||
if (descriptor.name.asString() != "contains") return false
|
||||
val containingClassDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return false
|
||||
if (!isTopLevelInPackage(containingClassDescriptor, "ClosedRange", "kotlin.ranges")) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun isPrimitiveRangeContains(descriptor: CallableDescriptor): Boolean {
|
||||
if (descriptor.name.asString() != "contains") return false
|
||||
val dispatchReceiverType = descriptor.dispatchReceiverParameter?.type ?: return false
|
||||
if (!isPrimitiveRange(dispatchReceiverType)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun isPrimitiveNumberRangeExtensionContainsPrimitiveNumber(descriptor: CallableDescriptor): Boolean {
|
||||
if (descriptor.name.asString() != "contains") return false
|
||||
|
||||
val extensionReceiverType = descriptor.extensionReceiverParameter?.type ?: return false
|
||||
|
||||
val rangeElementType = getRangeOrProgressionElementType(extensionReceiverType) ?: return false
|
||||
if (!isPrimitiveNumberType(rangeElementType)) return false
|
||||
|
||||
val argumentType = descriptor.valueParameters.singleOrNull()?.type ?: return false
|
||||
if (!isPrimitiveNumberType(argumentType)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun isPrimitiveNumberType(type: KotlinType) =
|
||||
KotlinBuiltIns.isByte(type) ||
|
||||
KotlinBuiltIns.isShort(type) ||
|
||||
KotlinBuiltIns.isInt(type) ||
|
||||
KotlinBuiltIns.isChar(type) ||
|
||||
KotlinBuiltIns.isLong(type) ||
|
||||
KotlinBuiltIns.isFloat(type) ||
|
||||
KotlinBuiltIns.isDouble(type)
|
||||
|
||||
fun isClosedFloatingPointRangeContains(descriptor: CallableDescriptor): Boolean {
|
||||
if (descriptor.name.asString() != "contains") return false
|
||||
val containingClassDescriptor = descriptor.containingDeclaration as? ClassDescriptor ?: return false
|
||||
if (!isTopLevelInPackage(containingClassDescriptor, "ClosedFloatingPointRange", "kotlin.ranges")) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun getClosedFloatingPointRangeElementType(rangeType: KotlinType): KotlinType? {
|
||||
val classDescriptor = rangeType.constructor.declarationDescriptor as? ClassDescriptor ?: return null
|
||||
if (!isTopLevelInPackage(classDescriptor, "ClosedFloatingPointRange", "kotlin.ranges")) return null
|
||||
return rangeType.arguments.singleOrNull()?.type
|
||||
}
|
||||
|
||||
private fun isTopLevelInPackage(descriptor: DeclarationDescriptor, name: String, packageName: String): Boolean {
|
||||
if (name != descriptor.name.asString()) return false
|
||||
|
||||
val containingDeclaration = descriptor.containingDeclaration as? PackageFragmentDescriptor ?: return false
|
||||
val packageFqName = containingDeclaration.fqName.asString()
|
||||
return packageName == packageFqName
|
||||
}
|
||||
|
||||
fun getAsmRangeElementTypeForPrimitiveRangeOrProgression(rangeCallee: CallableDescriptor): Type {
|
||||
val rangeType = rangeCallee.returnType!!
|
||||
|
||||
getPrimitiveRangeElementType(rangeType)?.let {
|
||||
return AsmTypes.valueTypeForPrimitive(it)
|
||||
}
|
||||
|
||||
getPrimitiveProgressionElementType(rangeType)?.let {
|
||||
return AsmTypes.valueTypeForPrimitive(it)
|
||||
}
|
||||
|
||||
getClosedFloatingPointRangeElementType(rangeType)?.let {
|
||||
when {
|
||||
KotlinBuiltIns.isDouble(it) -> return Type.DOUBLE_TYPE
|
||||
KotlinBuiltIns.isFloat(it) -> return Type.FLOAT_TYPE
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
throw AssertionError("Unexpected range type: $rangeType")
|
||||
}
|
||||
@@ -50,7 +50,7 @@ public class SamType {
|
||||
@NotNull
|
||||
public KotlinType getKotlinFunctionType() {
|
||||
//noinspection ConstantConditions
|
||||
return getJavaClassDescriptor().getFunctionTypeForSamInterface();
|
||||
return getJavaClassDescriptor().getDefaultFunctionTypeForSamInterface();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -105,14 +105,10 @@ public class ScriptCodegen extends MemberCodegen<KtScript> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateSyntheticPartsBeforeBody() {
|
||||
protected void generateSyntheticParts() {
|
||||
generatePropertyMetadataArrayFieldIfNeeded(classAsmType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateSyntheticPartsAfterBody() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateKotlinMetadataAnnotation() {
|
||||
generateKotlinClassMetadataAnnotation(scriptDescriptor, true);
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import kotlin.Unit;
|
||||
import kotlin.collections.ArraysKt;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -26,6 +27,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType;
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods;
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.JavaClassProperty;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
|
||||
@@ -515,11 +518,9 @@ public abstract class StackValue {
|
||||
descriptor
|
||||
);
|
||||
StackValue extensionReceiver = genReceiver(receiver, codegen, resolvedCall, callableMethod, callExtensionReceiver, true);
|
||||
return CallReceiver.generateCallReceiver(
|
||||
resolvedCall, codegen, callableMethod,
|
||||
dispatchReceiverParameter, dispatchReceiver,
|
||||
extensionReceiverParameter, extensionReceiver
|
||||
);
|
||||
Type type = CallReceiver.calcType(resolvedCall, dispatchReceiverParameter, extensionReceiverParameter, codegen.typeMapper, callableMethod, codegen.getState());
|
||||
assert type != null : "Could not map receiver type for " + resolvedCall;
|
||||
return new CallReceiver(dispatchReceiver, extensionReceiver, type);
|
||||
}
|
||||
return receiver;
|
||||
}
|
||||
@@ -568,13 +569,14 @@ public abstract class StackValue {
|
||||
}
|
||||
|
||||
@Contract("null -> false")
|
||||
static boolean isLocalFunCall(@Nullable Callable callableMethod) {
|
||||
private static boolean isLocalFunCall(@Nullable Callable callableMethod) {
|
||||
return callableMethod != null && callableMethod.getGenerateCalleeType() != null;
|
||||
}
|
||||
|
||||
public static StackValue receiverWithoutReceiverArgument(StackValue receiverWithParameter) {
|
||||
if (receiverWithParameter instanceof CallReceiver) {
|
||||
return ((CallReceiver) receiverWithParameter).withoutReceiverArgument();
|
||||
CallReceiver callReceiver = (CallReceiver) receiverWithParameter;
|
||||
return new CallReceiver(callReceiver.dispatchReceiver, none(), callReceiver.type);
|
||||
}
|
||||
return receiverWithParameter;
|
||||
}
|
||||
@@ -1515,6 +1517,101 @@ public abstract class StackValue {
|
||||
}
|
||||
}
|
||||
|
||||
public static class CallReceiver extends StackValue {
|
||||
private final StackValue dispatchReceiver;
|
||||
private final StackValue extensionReceiver;
|
||||
|
||||
public CallReceiver(
|
||||
@NotNull StackValue dispatchReceiver,
|
||||
@NotNull StackValue extensionReceiver,
|
||||
@NotNull Type type
|
||||
) {
|
||||
super(type, dispatchReceiver.canHaveSideEffects() || extensionReceiver.canHaveSideEffects());
|
||||
this.dispatchReceiver = dispatchReceiver;
|
||||
this.extensionReceiver = extensionReceiver;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Type calcType(
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@Nullable ReceiverParameterDescriptor dispatchReceiver,
|
||||
@Nullable ReceiverParameterDescriptor extensionReceiver,
|
||||
@NotNull KotlinTypeMapper typeMapper,
|
||||
@Nullable Callable callableMethod,
|
||||
@NotNull GenerationState state
|
||||
) {
|
||||
if (extensionReceiver != null) {
|
||||
CallableDescriptor descriptor = resolvedCall.getCandidateDescriptor();
|
||||
|
||||
if (descriptor instanceof PropertyDescriptor &&
|
||||
// hackaround: boxing changes behaviour of T.javaClass intrinsic
|
||||
state.getIntrinsics().getIntrinsic((PropertyDescriptor) descriptor) != JavaClassProperty.INSTANCE
|
||||
) {
|
||||
ReceiverParameterDescriptor receiverCandidate = descriptor.getExtensionReceiverParameter();
|
||||
assert receiverCandidate != null;
|
||||
return typeMapper.mapType(receiverCandidate.getType());
|
||||
}
|
||||
|
||||
return callableMethod != null ? callableMethod.getExtensionReceiverType() : typeMapper.mapType(extensionReceiver.getType());
|
||||
}
|
||||
else if (dispatchReceiver != null) {
|
||||
CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
|
||||
|
||||
if (CodegenUtilKt.isJvmStaticInObjectOrClass(descriptor)) {
|
||||
return Type.VOID_TYPE;
|
||||
}
|
||||
|
||||
if (callableMethod != null) {
|
||||
return callableMethod.getDispatchReceiverType();
|
||||
}
|
||||
|
||||
// Extract the receiver from the resolved call, workarounding the fact that ResolvedCall#dispatchReceiver doesn't have
|
||||
// all the needed information, for example there's no way to find out whether or not a smart cast was applied to the receiver.
|
||||
DeclarationDescriptor container = descriptor.getContainingDeclaration();
|
||||
if (container instanceof ClassDescriptor) {
|
||||
return typeMapper.mapClass((ClassDescriptor) container);
|
||||
}
|
||||
|
||||
return typeMapper.mapType(dispatchReceiver);
|
||||
}
|
||||
else if (isLocalFunCall(callableMethod)) {
|
||||
return callableMethod.getGenerateCalleeType();
|
||||
}
|
||||
|
||||
return Type.VOID_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
|
||||
StackValue currentExtensionReceiver = extensionReceiver;
|
||||
boolean hasExtensionReceiver = extensionReceiver != none();
|
||||
if (extensionReceiver instanceof StackValue.SafeCall) {
|
||||
currentExtensionReceiver.put(currentExtensionReceiver.type, v);
|
||||
currentExtensionReceiver = StackValue.onStack(currentExtensionReceiver.type);
|
||||
}
|
||||
|
||||
dispatchReceiver.put(hasExtensionReceiver ? dispatchReceiver.type : type, v);
|
||||
|
||||
currentExtensionReceiver
|
||||
.moveToTopOfStack(hasExtensionReceiver ? type : currentExtensionReceiver.type, v, dispatchReceiver.type.getSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dup(@NotNull InstructionAdapter v, boolean withReceiver) {
|
||||
AsmUtil.dup(v, extensionReceiver.type, dispatchReceiver.type);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StackValue getDispatchReceiver() {
|
||||
return dispatchReceiver;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StackValue getExtensionReceiver() {
|
||||
return extensionReceiver;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class StackValueWithSimpleReceiver extends StackValue {
|
||||
|
||||
public final boolean isStaticPut;
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotatedImpl
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
interface WrappedAnnotated : Annotated {
|
||||
val originalAnnotated: Annotated
|
||||
@@ -33,6 +34,10 @@ class AnnotatedWithOnlyTargetedAnnotations(original: Annotated) : Annotated {
|
||||
private class UseSiteTargetedAnnotations(private val additionalAnnotations: Annotations) : Annotations {
|
||||
override fun isEmpty() = true
|
||||
|
||||
override fun findAnnotation(fqName: FqName) = null
|
||||
|
||||
override fun findExternalAnnotation(fqName: FqName) = null
|
||||
|
||||
override fun getUseSiteTargetedAnnotations() = getAdditionalTargetedAnnotations()
|
||||
|
||||
override fun getAllAnnotations() = getAdditionalTargetedAnnotations()
|
||||
@@ -43,4 +48,4 @@ class AnnotatedWithOnlyTargetedAnnotations(original: Annotated) : Annotated {
|
||||
}
|
||||
}
|
||||
|
||||
class AnnotatedSimple(annotations: Annotations) : AnnotatedImpl(annotations)
|
||||
class AnnotatedSimple(annotations: Annotations) : AnnotatedImpl(annotations)
|
||||
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.kotlin.fileClasses.FileClasses;
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor;
|
||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingConfiguration;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
@@ -439,9 +440,15 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
// The first "real" containing class (not a synthetic class for lambda) is the owner of the delegated property metadata
|
||||
if (!(descriptor instanceof SyntheticClassDescriptorForLambda)) {
|
||||
ClassId classId = DescriptorUtilsKt.getClassId(descriptor);
|
||||
return classId != null
|
||||
? AsmUtil.asmTypeByClassId(classId)
|
||||
: CodegenBinding.getAsmType(bindingContext, descriptor);
|
||||
if (classId == null) {
|
||||
return CodegenBinding.getAsmType(bindingContext, descriptor);
|
||||
}
|
||||
|
||||
return AsmUtil.asmTypeByClassId(
|
||||
DescriptorUtils.isInterface(descriptor)
|
||||
? classId.createNestedClassId(Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME))
|
||||
: classId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -413,10 +413,4 @@ fun extractReificationArgument(type: KotlinType): Pair<TypeParameterDescriptor,
|
||||
}
|
||||
|
||||
fun unwrapInitialSignatureDescriptor(function: FunctionDescriptor): FunctionDescriptor =
|
||||
function.initialSignatureDescriptor ?: function
|
||||
|
||||
fun ExpressionCodegen.generateCallReceiver(rangeCall: ResolvedCall<out CallableDescriptor>): StackValue =
|
||||
generateReceiverValue(rangeCall.extensionReceiver ?: rangeCall.dispatchReceiver!!, false)
|
||||
|
||||
fun ExpressionCodegen.generateCallSingleArgument(rangeCall: ResolvedCall<out CallableDescriptor>): StackValue =
|
||||
gen(ExpressionCodegen.getSingleArgumentExpression(rangeCall)!!)
|
||||
function.initialSignatureDescriptor ?: function
|
||||
@@ -63,7 +63,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
|
||||
private val classBuilderForCoroutineState: ClassBuilder by lazy(obtainClassBuilderForCoroutineState)
|
||||
|
||||
private val continuationIndex = if (isForNamedFunction) getLastParameterIndex(desc, access) else 0
|
||||
private var continuationIndex = if (isForNamedFunction) -1 else 0
|
||||
private var dataIndex = if (isForNamedFunction) -1 else 1
|
||||
private var exceptionIndex = if (isForNamedFunction) -1 else 2
|
||||
|
||||
@@ -83,6 +83,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
|
||||
dataIndex = methodNode.maxLocals++
|
||||
exceptionIndex = methodNode.maxLocals++
|
||||
continuationIndex = methodNode.maxLocals++
|
||||
|
||||
prepareMethodNodePreludeForNamedFunction(methodNode)
|
||||
}
|
||||
@@ -111,11 +112,12 @@ class CoroutineTransformerMethodVisitor(
|
||||
methodNode.instructions.apply {
|
||||
val startLabel = LabelNode()
|
||||
val defaultLabel = LabelNode()
|
||||
val firstToInsertBefore = actualCoroutineStart
|
||||
val tableSwitchLabel = LabelNode()
|
||||
val lineNumber = CodegenUtil.getLineNumberForElement(element, false) ?: 0
|
||||
|
||||
// tableswitch(this.label)
|
||||
insertBefore(actualCoroutineStart,
|
||||
insertBefore(firstToInsertBefore,
|
||||
insnListOf(
|
||||
*withInstructionAdapter { loadCoroutineSuspendedMarker() }.toArray(),
|
||||
tableSwitchLabel,
|
||||
@@ -194,6 +196,13 @@ class CoroutineTransformerMethodVisitor(
|
||||
|
||||
private fun prepareMethodNodePreludeForNamedFunction(methodNode: MethodNode) {
|
||||
val objectTypeForState = Type.getObjectType(classBuilderForCoroutineState.thisName)
|
||||
val continuationArgumentIndex = getLastParameterIndex(methodNode.desc, methodNode.access)
|
||||
methodNode.instructions.asSequence().filterIsInstance<VarInsnNode>().forEach {
|
||||
if (it.`var` != continuationArgumentIndex) return@forEach
|
||||
assert(it.opcode == Opcodes.ALOAD) { "Only ALOADs are allowed for continuation arguments" }
|
||||
it.`var` = continuationIndex
|
||||
}
|
||||
|
||||
methodNode.instructions.insert(withInstructionAdapter {
|
||||
val createStateInstance = Label()
|
||||
val afterCoroutineStateCreated = Label()
|
||||
@@ -212,11 +221,12 @@ class CoroutineTransformerMethodVisitor(
|
||||
// - Otherwise it's still can be a recursive call. To check it's not the case we set the last bit in the label in
|
||||
// `doResume` just before calling the suspend function (see kotlin.coroutines.experimental.jvm.internal.CoroutineImplForNamedFunction).
|
||||
// So, if it's set we're in continuation.
|
||||
visitVarInsn(Opcodes.ALOAD, continuationIndex)
|
||||
|
||||
visitVarInsn(Opcodes.ALOAD, continuationArgumentIndex)
|
||||
instanceOf(objectTypeForState)
|
||||
ifeq(createStateInstance)
|
||||
|
||||
visitVarInsn(Opcodes.ALOAD, continuationIndex)
|
||||
visitVarInsn(Opcodes.ALOAD, continuationArgumentIndex)
|
||||
checkcast(objectTypeForState)
|
||||
visitVarInsn(Opcodes.ASTORE, continuationIndex)
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ internal fun performRefinedTypeAnalysis(methodNode: MethodNode, thisName: String
|
||||
}
|
||||
})
|
||||
|
||||
return Array(basicFrames.size) {
|
||||
val refinedFrames = Array(basicFrames.size) {
|
||||
insnIndex ->
|
||||
val current = Frame(basicFrames[insnIndex] ?: return@Array null)
|
||||
|
||||
@@ -158,6 +158,8 @@ internal fun performRefinedTypeAnalysis(methodNode: MethodNode, thisName: String
|
||||
|
||||
current
|
||||
}
|
||||
|
||||
return refinedFrames
|
||||
}
|
||||
|
||||
private fun AbstractInsnNode.isIntLoad() = opcode == Opcodes.ILOAD
|
||||
|
||||
@@ -14,9 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.range.forLoop
|
||||
package org.jetbrains.kotlin.codegen.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
@@ -24,7 +25,15 @@ import org.jetbrains.org.objectweb.asm.Type
|
||||
abstract class AbstractForInExclusiveRangeLoopGenerator(
|
||||
codegen: ExpressionCodegen,
|
||||
forExpression: KtForExpression
|
||||
) : AbstractForInRangeWithGivenBoundsLoopGenerator(codegen, forExpression) {
|
||||
) : AbstractForInRangeLoopGenerator(codegen, forExpression) {
|
||||
protected abstract fun generateFrom(): StackValue
|
||||
protected abstract fun generateTo(): StackValue
|
||||
|
||||
override fun storeRangeStartAndEnd() {
|
||||
loopParameter().store(generateFrom(), v)
|
||||
StackValue.local(endVar, asmElementType).store(generateTo(), v)
|
||||
}
|
||||
|
||||
override fun checkEmptyLoop(loopExit: Label) {}
|
||||
|
||||
override fun checkPreCondition(loopExit: Label) {
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.range.forLoop
|
||||
package org.jetbrains.kotlin.codegen.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
@@ -25,7 +25,7 @@ import org.jetbrains.org.objectweb.asm.Type
|
||||
abstract class AbstractForInProgressionOrRangeLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression)
|
||||
: AbstractForLoopGenerator(codegen, forExpression)
|
||||
{
|
||||
protected var endVar: Int = -1
|
||||
protected var endVar: Int = 0
|
||||
|
||||
private var loopParameter: StackValue? = null
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.range.forLoop
|
||||
package org.jetbrains.kotlin.codegen.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.range.forLoop
|
||||
package org.jetbrains.kotlin.codegen.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
@@ -30,8 +30,8 @@ import org.jetbrains.org.objectweb.asm.Type
|
||||
|
||||
abstract class AbstractForLoopGenerator(
|
||||
protected val codegen: ExpressionCodegen,
|
||||
override val forExpression: KtForExpression
|
||||
) : ForLoopGenerator {
|
||||
val forExpression: KtForExpression
|
||||
) {
|
||||
protected val bindingContext = codegen.bindingContext
|
||||
protected val v = codegen.v!!
|
||||
|
||||
@@ -42,7 +42,7 @@ abstract class AbstractForLoopGenerator(
|
||||
protected val elementType: KotlinType = bindingContext.getElementType(forExpression)
|
||||
protected val asmElementType: Type = codegen.asmType(elementType)
|
||||
|
||||
protected var loopParameterVar: Int = -1
|
||||
protected var loopParameterVar: Int = 0
|
||||
protected lateinit var loopParameterType: Type
|
||||
|
||||
private fun BindingContext.getElementType(forExpression: KtForExpression): KotlinType {
|
||||
@@ -52,7 +52,7 @@ abstract class AbstractForLoopGenerator(
|
||||
return nextCall.resultingDescriptor.returnType!!
|
||||
}
|
||||
|
||||
override fun beforeLoop() {
|
||||
open fun beforeLoop() {
|
||||
val loopParameter = forExpression.loopParameter ?: return
|
||||
val multiParameter = loopParameter.destructuringDeclaration
|
||||
if (multiParameter != null) {
|
||||
@@ -75,7 +75,11 @@ abstract class AbstractForLoopGenerator(
|
||||
}
|
||||
}
|
||||
|
||||
override fun beforeBody() {
|
||||
abstract fun checkEmptyLoop(loopExit: Label)
|
||||
|
||||
abstract fun checkPreCondition(loopExit: Label)
|
||||
|
||||
fun beforeBody() {
|
||||
assignToLoopParameter()
|
||||
v.mark(loopParameterStartLabel)
|
||||
|
||||
@@ -114,7 +118,7 @@ abstract class AbstractForLoopGenerator(
|
||||
|
||||
protected abstract fun checkPostConditionAndIncrement(loopExit: Label)
|
||||
|
||||
override fun body() {
|
||||
fun body() {
|
||||
codegen.generateLoopBody(forExpression.body)
|
||||
}
|
||||
|
||||
@@ -128,7 +132,7 @@ abstract class AbstractForLoopGenerator(
|
||||
return varIndex
|
||||
}
|
||||
|
||||
override fun afterBody(loopExit: Label) {
|
||||
fun afterBody(loopExit: Label) {
|
||||
codegen.markStartLineNumber(forExpression)
|
||||
|
||||
checkPostConditionAndIncrement(loopExit)
|
||||
@@ -136,7 +140,7 @@ abstract class AbstractForLoopGenerator(
|
||||
v.mark(bodyEnd)
|
||||
}
|
||||
|
||||
override fun afterLoop() {
|
||||
fun afterLoop() {
|
||||
for (task in leaveVariableTasks.asReversed()) {
|
||||
task.run()
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.range.forLoop
|
||||
package org.jetbrains.kotlin.codegen.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.range.forLoop
|
||||
package org.jetbrains.kotlin.codegen.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.range.forLoop
|
||||
package org.jetbrains.kotlin.codegen.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.range.forLoop
|
||||
package org.jetbrains.kotlin.codegen.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.range.forLoop
|
||||
package org.jetbrains.kotlin.codegen.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.range.forLoop
|
||||
package org.jetbrains.kotlin.codegen.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
@@ -27,11 +27,12 @@ class ForInDownToProgressionLoopGenerator(
|
||||
codegen: ExpressionCodegen,
|
||||
forExpression: KtForExpression,
|
||||
loopRangeCall: ResolvedCall<*>
|
||||
) : AbstractForInRangeWithGivenBoundsLoopGenerator(codegen, forExpression, -1) {
|
||||
) : AbstractForInRangeLoopGenerator(codegen, forExpression, -1) {
|
||||
private val from: ReceiverValue = loopRangeCall.extensionReceiver!!
|
||||
private val to: KtExpression = ExpressionCodegen.getSingleArgumentExpression(loopRangeCall)!!
|
||||
|
||||
override fun generateFrom(): StackValue = codegen.generateReceiverValue(from, false)
|
||||
|
||||
override fun generateTo(): StackValue = codegen.gen(to)
|
||||
override fun storeRangeStartAndEnd() {
|
||||
loopParameter().store(codegen.generateReceiverValue(from, false), v)
|
||||
StackValue.local(endVar, asmElementType).store(codegen.gen(to), v)
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.range.forLoop
|
||||
package org.jetbrains.kotlin.codegen.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.range.forLoop
|
||||
package org.jetbrains.kotlin.codegen.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
@@ -24,36 +24,38 @@ import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
|
||||
abstract class AbstractForInProgressionLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression)
|
||||
class ForInProgressionExpressionLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression)
|
||||
: AbstractForInProgressionOrRangeLoopGenerator(codegen, forExpression)
|
||||
{
|
||||
protected var incrementVar: Int = -1
|
||||
protected val asmLoopRangeType: Type
|
||||
protected val incrementType: Type
|
||||
|
||||
init {
|
||||
val loopRangeType = bindingContext.getType(forExpression.loopRange!!)!!
|
||||
asmLoopRangeType = codegen.asmType(loopRangeType)
|
||||
|
||||
val incrementProp = loopRangeType.memberScope.getContributedVariables(Name.identifier("step"), NoLookupLocation.FROM_BACKEND)
|
||||
assert(incrementProp.size == 1) { loopRangeType.toString() + " " + incrementProp.size }
|
||||
incrementType = codegen.asmType(incrementProp.iterator().next().type)
|
||||
}
|
||||
private var incrementVar: Int = 0
|
||||
private var incrementType: Type? = null
|
||||
|
||||
override fun beforeLoop() {
|
||||
super.beforeLoop()
|
||||
|
||||
incrementVar = createLoopTempVariable(asmElementType)
|
||||
|
||||
storeProgressionParametersToLocalVars()
|
||||
}
|
||||
val loopRangeType = bindingContext.getType(forExpression.loopRange!!)!!
|
||||
val asmLoopRangeType = codegen.asmType(loopRangeType)
|
||||
|
||||
protected abstract fun storeProgressionParametersToLocalVars()
|
||||
val incrementProp = loopRangeType.memberScope.getContributedVariables(Name.identifier("step"), NoLookupLocation.FROM_BACKEND)
|
||||
assert(incrementProp.size == 1) { loopRangeType.toString() + " " + incrementProp.size }
|
||||
incrementType = codegen.asmType(incrementProp.iterator().next().type)
|
||||
|
||||
codegen.gen(forExpression.loopRange, asmLoopRangeType)
|
||||
v.dup()
|
||||
v.dup()
|
||||
|
||||
generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterType,
|
||||
loopParameterVar)
|
||||
generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, asmElementType, endVar)
|
||||
generateRangeOrProgressionProperty(asmLoopRangeType, "getStep", incrementType!!, incrementType!!, incrementVar)
|
||||
}
|
||||
|
||||
override fun checkEmptyLoop(loopExit: Label) {
|
||||
loopParameter().put(asmElementType, v)
|
||||
v.load(endVar, asmElementType)
|
||||
v.load(incrementVar, incrementType)
|
||||
v.load(incrementVar, incrementType!!)
|
||||
|
||||
val negativeIncrement = Label()
|
||||
val afterIf = Label()
|
||||
@@ -104,4 +106,4 @@ abstract class AbstractForInProgressionLoopGenerator(codegen: ExpressionCodegen,
|
||||
|
||||
loopParameter.store(StackValue.onStack(asmElementType), v)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.range.forLoop
|
||||
package org.jetbrains.kotlin.codegen.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
@@ -31,7 +31,8 @@ class ForInRangeInstanceLoopGenerator(
|
||||
v.dup()
|
||||
|
||||
// ranges inherit first and last from corresponding progressions
|
||||
generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterType, loopParameterVar)
|
||||
generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterType,
|
||||
loopParameterVar)
|
||||
generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, asmElementType, endVar)
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.range.forLoop
|
||||
package org.jetbrains.kotlin.codegen.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
@@ -27,16 +27,12 @@ class ForInRangeLiteralLoopGenerator(
|
||||
codegen: ExpressionCodegen,
|
||||
forExpression: KtForExpression,
|
||||
loopRangeCall: ResolvedCall<*>
|
||||
) : AbstractForInRangeWithGivenBoundsLoopGenerator(codegen, forExpression) {
|
||||
) : AbstractForInRangeLoopGenerator(codegen, forExpression) {
|
||||
private val from: ReceiverValue = loopRangeCall.dispatchReceiver!!
|
||||
private val to: KtExpression = ExpressionCodegen.getSingleArgumentExpression(loopRangeCall)!!
|
||||
|
||||
override fun generateFrom(): StackValue = codegen.generateReceiverValue(from, false)
|
||||
|
||||
override fun generateTo(): StackValue = codegen.gen(to)
|
||||
|
||||
override fun storeRangeStartAndEnd() {
|
||||
loopParameter().store(generateFrom(), v)
|
||||
StackValue.local(endVar, asmElementType).store(generateTo(), v)
|
||||
loopParameter().store(codegen.generateReceiverValue(from, false), codegen.v)
|
||||
StackValue.local(endVar, asmElementType).store(codegen.gen(to), codegen.v)
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.range.forLoop
|
||||
package org.jetbrains.kotlin.codegen.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.RangeCodegenUtil
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
|
||||
fun ExpressionCodegen.getForLoopGenerator(forExpression: KtForExpression) : AbstractForLoopGenerator {
|
||||
getLoopRangeResolvedCall(forExpression, bindingContext)?.let { loopRangeCall ->
|
||||
createOptimizedForLoopGeneratorOrNull(forExpression, loopRangeCall)?.let {
|
||||
return it
|
||||
}
|
||||
}
|
||||
|
||||
val loopRange = forExpression.loopRange!!
|
||||
val loopRangeType = bindingContext.getType(loopRange)!!
|
||||
val asmLoopRangeType = asmType(loopRangeType)
|
||||
|
||||
return when {
|
||||
asmLoopRangeType.sort == Type.ARRAY ->
|
||||
ForInArrayLoopGenerator(this, forExpression)
|
||||
RangeCodegenUtil.isRange(loopRangeType) ->
|
||||
ForInRangeInstanceLoopGenerator(this, forExpression)
|
||||
RangeCodegenUtil.isProgression(loopRangeType) ->
|
||||
ForInProgressionExpressionLoopGenerator(this, forExpression)
|
||||
isSubtypeOfCharSequence(loopRangeType, state.module.builtIns) ->
|
||||
ForInCharSequenceLoopGenerator(this, forExpression)
|
||||
else ->
|
||||
IteratorForLoopGenerator(this, forExpression)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSubtypeOfCharSequence(type: KotlinType, builtIns: KotlinBuiltIns) =
|
||||
KotlinTypeChecker.DEFAULT.isSubtypeOf(type, builtIns.getBuiltInClassByName(Name.identifier("CharSequence")).defaultType)
|
||||
|
||||
private fun ExpressionCodegen.createOptimizedForLoopGeneratorOrNull(
|
||||
forExpression: KtForExpression,
|
||||
loopRangeCall: ResolvedCall<out CallableDescriptor>
|
||||
): AbstractForLoopGenerator? {
|
||||
val loopRangeCallee = loopRangeCall.resultingDescriptor
|
||||
|
||||
return when {
|
||||
RangeCodegenUtil.isPrimitiveNumberRangeTo(loopRangeCallee) ->
|
||||
ForInRangeLiteralLoopGenerator(this, forExpression, loopRangeCall)
|
||||
RangeCodegenUtil.isPrimitiveNumberDownTo(loopRangeCallee) ->
|
||||
ForInDownToProgressionLoopGenerator(this, forExpression, loopRangeCall)
|
||||
RangeCodegenUtil.isPrimitiveNumberUntil(loopRangeCallee) ->
|
||||
ForInUntilRangeLoopGenerator(this, forExpression, loopRangeCall)
|
||||
RangeCodegenUtil.isArrayOrPrimitiveArrayIndices(loopRangeCallee) ->
|
||||
ForInArrayIndicesRangeLoopGenerator(this, forExpression, loopRangeCall)
|
||||
RangeCodegenUtil.isCollectionIndices(loopRangeCallee) ->
|
||||
ForInCollectionIndicesRangeLoopGenerator(this, forExpression, loopRangeCall)
|
||||
RangeCodegenUtil.isCharSequenceIndices(loopRangeCallee) ->
|
||||
ForInCharSequenceIndicesRangeLoopGenerator(this, forExpression, loopRangeCall)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLoopRangeResolvedCall(forExpression: KtForExpression, bindingContext: BindingContext): ResolvedCall<out CallableDescriptor>? {
|
||||
val loopRange = KtPsiUtil.deparenthesize(forExpression.loopRange)
|
||||
|
||||
when (loopRange) {
|
||||
is KtQualifiedExpression -> {
|
||||
val qualifiedExpression = loopRange as KtQualifiedExpression?
|
||||
val selector = qualifiedExpression!!.selectorExpression
|
||||
if (selector is KtCallExpression || selector is KtSimpleNameExpression) {
|
||||
return selector.getResolvedCall(bindingContext)
|
||||
}
|
||||
}
|
||||
is KtSimpleNameExpression, is KtCallExpression -> return loopRange.getResolvedCall(bindingContext)
|
||||
is KtBinaryExpression -> return loopRange.operationReference.getResolvedCall(bindingContext)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.range.forLoop
|
||||
package org.jetbrains.kotlin.codegen.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
@@ -460,7 +460,7 @@ abstract class InlineCodegen<out T: BaseExpressionCodegen>(
|
||||
if (isBuiltInArrayIntrinsic(callableDescriptor)) {
|
||||
val classId = classId
|
||||
val bytes = state.inlineCache.classBytes.getOrPut(classId) { bytecode }
|
||||
return getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, classId.asString())
|
||||
return getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, AsmUtil.asmTypeByClassId(classId))
|
||||
}
|
||||
|
||||
assert(callableDescriptor is DeserializedCallableMemberDescriptor) { "Not a deserialized function or proper: " + callableDescriptor }
|
||||
@@ -474,7 +474,7 @@ abstract class InlineCodegen<out T: BaseExpressionCodegen>(
|
||||
throw IllegalStateException("Couldn't find declaration file for " + containerId)
|
||||
}
|
||||
|
||||
val methodNode = getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, containerId.asString()) ?: return null
|
||||
val methodNode = getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, AsmUtil.asmTypeByClassId(containerId)) ?: return null
|
||||
|
||||
// KLUDGE: Inline suspend function built with compiler version less than 1.1.4/1.2-M1 did not contain proper
|
||||
// before/after suspension point marks, so we detect those functions here and insert the corresponding marks
|
||||
@@ -530,7 +530,7 @@ abstract class InlineCodegen<out T: BaseExpressionCodegen>(
|
||||
val varDescriptor = field.descriptor
|
||||
//check that variable is inline function parameter
|
||||
return !(varDescriptor is ParameterDescriptor &&
|
||||
InlineUtil.isInlineLambdaParameter(varDescriptor) &&
|
||||
InlineUtil.isInlineParameter(varDescriptor) &&
|
||||
InlineUtil.isInline(varDescriptor.containingDeclaration))
|
||||
}
|
||||
|
||||
@@ -645,7 +645,7 @@ class PsiInlineCodegen(
|
||||
//TODO deparenthisise typed
|
||||
val deparenthesized = KtPsiUtil.deparenthesize(expression)
|
||||
|
||||
return InlineUtil.isInlineLambdaParameter(valueParameterDescriptor) && isInlinableParameterExpression(deparenthesized)
|
||||
return InlineUtil.isInlineParameter(valueParameterDescriptor) && isInlinableParameterExpression(deparenthesized)
|
||||
}
|
||||
|
||||
override fun genValueAndPut(
|
||||
|
||||
@@ -135,7 +135,7 @@ class DefaultLambda(
|
||||
classReader.b,
|
||||
"<init>",
|
||||
descriptor,
|
||||
lambdaClassType.internalName)?.node
|
||||
lambdaClassType)?.node
|
||||
|
||||
assert(constructor != null || capturedArgs.isEmpty()) {
|
||||
"Can't find non-default constructor <init>$descriptor for default lambda $lambdaClassType"
|
||||
@@ -164,7 +164,7 @@ class DefaultLambda(
|
||||
classReader.b,
|
||||
invokeMethod.name,
|
||||
invokeMethod.descriptor,
|
||||
lambdaClassType.internalName)!!
|
||||
lambdaClassType)!!
|
||||
|
||||
if (needReification) {
|
||||
//nested classes could also require reification
|
||||
|
||||
@@ -619,11 +619,11 @@ class MethodInliner(
|
||||
}
|
||||
|
||||
private fun wrapException(originalException: Throwable, node: MethodNode, errorSuffix: String): RuntimeException {
|
||||
return if (originalException is InlineException) {
|
||||
InlineException("$errorPrefix: $errorSuffix", originalException)
|
||||
if (originalException is InlineException) {
|
||||
return InlineException("$errorPrefix: $errorSuffix", originalException)
|
||||
}
|
||||
else {
|
||||
InlineException("$errorPrefix: $errorSuffix\nCause: ${node.nodeText}", originalException)
|
||||
return InlineException("$errorPrefix: $errorSuffix\nCause: ${node.nodeText}", originalException)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -679,11 +679,11 @@ class MethodInliner(
|
||||
localReturns.add(LocalReturn(returnInsn, insertBeforeInsn, sourceValueFrame))
|
||||
|
||||
if (returnInsn.opcode != Opcodes.RETURN) {
|
||||
returnVariableSize = if (returnInsn.opcode == Opcodes.LRETURN || returnInsn.opcode == Opcodes.DRETURN) {
|
||||
2
|
||||
if (returnInsn.opcode == Opcodes.LRETURN || returnInsn.opcode == Opcodes.DRETURN) {
|
||||
returnVariableSize = 2
|
||||
}
|
||||
else {
|
||||
1
|
||||
returnVariableSize = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -716,9 +716,10 @@ class MethodInliner(
|
||||
"Captured field template should start with $CAPTURED_FIELD_FOLD_PREFIX prefix"
|
||||
}
|
||||
val fin = FieldInsnNode(node.opcode, node.owner, node.name.substring(3), node.desc)
|
||||
return fieldRemapper.findField(fin) ?: throw IllegalStateException(
|
||||
val field = fieldRemapper.findField(fin) ?: throw IllegalStateException(
|
||||
"Couldn't find captured field ${node.owner}.${node.name} in ${fieldRemapper.originalLambdaInternalName}"
|
||||
)
|
||||
return field
|
||||
}
|
||||
|
||||
private fun analyzeMethodNodeWithoutMandatoryTransformations(node: MethodNode): Array<Frame<SourceValue>?> {
|
||||
|
||||
@@ -98,8 +98,8 @@ open class NestedSourceMapper(
|
||||
override fun mapLineNumber(lineNumber: Int): Int {
|
||||
val mappedLineNumber = visitedLines.get(lineNumber)
|
||||
|
||||
return if (mappedLineNumber > 0) {
|
||||
mappedLineNumber
|
||||
if (mappedLineNumber > 0) {
|
||||
return mappedLineNumber
|
||||
}
|
||||
else {
|
||||
val rangeForMapping =
|
||||
@@ -111,7 +111,7 @@ open class NestedSourceMapper(
|
||||
visitedLines.put(lineNumber, newLineNumber)
|
||||
}
|
||||
lastVisitedRange = rangeForMapping
|
||||
newLineNumber
|
||||
return newLineNumber
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
@@ -94,6 +95,8 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid
|
||||
|
||||
private var context by Delegates.notNull<CodegenContext<*>>()
|
||||
|
||||
private var additionalInnerClasses = mutableListOf<ClassDescriptor>()
|
||||
|
||||
override val lookupLocation = KotlinLookupLocation(callElement)
|
||||
|
||||
|
||||
@@ -164,12 +167,15 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid
|
||||
if (isLambda)
|
||||
codegen.parentCodegen.className
|
||||
else
|
||||
state.typeMapper.mapImplementationOwner(descriptor).internalName
|
||||
state.typeMapper.mapImplementationOwner(descriptor).internalName,
|
||||
if (isLambda) emptyList() else additionalInnerClasses,
|
||||
isLambda
|
||||
)
|
||||
|
||||
val strategy = when (expression) {
|
||||
is KtCallableReferenceExpression -> {
|
||||
val receiverExpression = expression.receiverExpression
|
||||
val callableReferenceExpression = expression
|
||||
val receiverExpression = callableReferenceExpression.receiverExpression
|
||||
val receiverType = if (receiverExpression != null && state.bindingContext.getType(receiverExpression) != null)
|
||||
state.typeMapper.mapType(state.bindingContext.getType(receiverExpression)!!)
|
||||
else
|
||||
@@ -186,7 +192,7 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid
|
||||
FunctionReferenceGenerationStrategy(
|
||||
state,
|
||||
descriptor,
|
||||
expression.callableReference
|
||||
callableReferenceExpression.callableReference
|
||||
.getResolvedCallWithAssert(state.bindingContext),
|
||||
receiverType, null,
|
||||
true
|
||||
@@ -222,7 +228,9 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid
|
||||
internal val delegate: MemberCodegen<*>,
|
||||
declaration: KtElement,
|
||||
codegenContext: FieldOwnerContext<*>,
|
||||
private val className: String
|
||||
private val className: String,
|
||||
private val parentAsInnerClasses: List<ClassDescriptor>,
|
||||
private val isInlineLambdaCodegen: Boolean
|
||||
) : MemberCodegen<KtPureElement>(delegate as MemberCodegen<KtPureElement>, declaration, codegenContext) {
|
||||
|
||||
override fun generateDeclaration() {
|
||||
@@ -246,6 +254,14 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid
|
||||
return className
|
||||
}
|
||||
|
||||
override fun addParentsToInnerClassesIfNeeded(innerClasses: MutableCollection<ClassDescriptor>) {
|
||||
if (isInlineLambdaCodegen) {
|
||||
super.addParentsToInnerClassesIfNeeded(innerClasses)
|
||||
}
|
||||
else {
|
||||
innerClasses.addAll(parentAsInnerClasses)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun doCreateMethodNodeFromSource(
|
||||
@@ -278,7 +294,9 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid
|
||||
val implementationOwner = state.typeMapper.mapImplementationOwner(callableDescriptor)
|
||||
val parentCodegen = FakeMemberCodegen(
|
||||
codegen.parentCodegen, inliningFunction!!, methodContext.parentContext as FieldOwnerContext<*>,
|
||||
implementationOwner.internalName
|
||||
implementationOwner.internalName,
|
||||
additionalInnerClasses,
|
||||
false
|
||||
)
|
||||
if (element !is KtNamedFunction) {
|
||||
throw IllegalStateException("Property accessors with default parameters not supported " + callableDescriptor)
|
||||
@@ -389,22 +407,25 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid
|
||||
}
|
||||
|
||||
override fun initializeInlineFunctionContext(functionDescriptor: FunctionDescriptor) {
|
||||
context = getContext(functionDescriptor, state, DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor)?.containingFile as? KtFile)
|
||||
context = getContext(functionDescriptor, functionDescriptor, state, DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor)?.containingFile as? KtFile, additionalInnerClasses)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getContext(
|
||||
descriptor: DeclarationDescriptor, state: GenerationState, sourceFile: KtFile?
|
||||
descriptor: DeclarationDescriptor, innerDescriptor: DeclarationDescriptor, state: GenerationState, sourceFile: KtFile?, additionalInners: MutableList<ClassDescriptor>
|
||||
): CodegenContext<*> {
|
||||
if (descriptor is PackageFragmentDescriptor) {
|
||||
//no inners
|
||||
return PackageContext(descriptor, state.rootContext, null, sourceFile)
|
||||
}
|
||||
|
||||
val container = descriptor.containingDeclaration ?: error("No container for descriptor: " + descriptor)
|
||||
val parent = getContext(
|
||||
container,
|
||||
descriptor,
|
||||
state,
|
||||
sourceFile
|
||||
sourceFile,
|
||||
additionalInners
|
||||
)
|
||||
|
||||
return when (descriptor) {
|
||||
@@ -417,7 +438,14 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid
|
||||
)
|
||||
}
|
||||
is ClassDescriptor -> {
|
||||
val kind = if (DescriptorUtils.isInterface(descriptor)) OwnerKind.DEFAULT_IMPLS else OwnerKind.IMPLEMENTATION
|
||||
val kind =
|
||||
if (DescriptorUtils.isInterface(descriptor) && innerDescriptor !is ClassDescriptor)
|
||||
OwnerKind.DEFAULT_IMPLS
|
||||
else OwnerKind.IMPLEMENTATION
|
||||
|
||||
additionalInners.addIfNotNull(
|
||||
InnerClassConsumer.classForInnerClassRecord(descriptor, kind == OwnerKind.DEFAULT_IMPLS)
|
||||
)
|
||||
parent.intoClass(descriptor, kind, state)
|
||||
}
|
||||
is FunctionDescriptor -> {
|
||||
|
||||
@@ -51,7 +51,7 @@ fun extractDefaultLambdaOffsetAndDescriptor(jvmSignature: JvmMethodSignature, fu
|
||||
val valueParameterOffset = valueParameters.takeWhile { it.kind != JvmMethodParameterKind.VALUE }.size
|
||||
|
||||
return functionDescriptor.valueParameters.filter {
|
||||
InlineUtil.isInlineLambdaParameter(it) && it.declaresDefaultValue()
|
||||
InlineUtil.isInlineParameter(it) && it.declaresDefaultValue()
|
||||
}.associateBy {
|
||||
parameterOffsets[valueParameterOffset + it.index]
|
||||
}
|
||||
|
||||
@@ -89,12 +89,13 @@ private const val INLINE_MARKER_FINALLY_START = "finallyStart"
|
||||
private const val INLINE_MARKER_FINALLY_END = "finallyEnd"
|
||||
private const val INLINE_MARKER_BEFORE_SUSPEND_ID = 0
|
||||
private const val INLINE_MARKER_AFTER_SUSPEND_ID = 1
|
||||
private val INTRINSIC_ARRAY_CONSTRUCTOR_TYPE = AsmUtil.asmTypeByClassId(classId)
|
||||
|
||||
internal fun getMethodNode(
|
||||
classData: ByteArray,
|
||||
methodName: String,
|
||||
methodDescriptor: String,
|
||||
classInternalName: String
|
||||
classType: Type
|
||||
): SMAPAndMethodNode? {
|
||||
val cr = ClassReader(classData)
|
||||
var node: MethodNode? = null
|
||||
@@ -136,12 +137,12 @@ internal fun getMethodNode(
|
||||
return null
|
||||
}
|
||||
|
||||
if (classId.asString() == classInternalName) {
|
||||
if (INTRINSIC_ARRAY_CONSTRUCTOR_TYPE == classType) {
|
||||
// Don't load source map for intrinsic array constructors
|
||||
debugInfo[0] = null
|
||||
}
|
||||
|
||||
val smap = SMAPParser.parseOrCreateDefault(debugInfo[1], debugInfo[0], classInternalName, lines[0], lines[1])
|
||||
val smap = SMAPParser.parseOrCreateDefault(debugInfo[1], debugInfo[0], classType.internalName, lines[0], lines[1])
|
||||
return SMAPAndMethodNode(node!!, smap)
|
||||
}
|
||||
|
||||
@@ -286,8 +287,9 @@ internal fun getMarkedReturnLabelOrNull(returnInsn: AbstractInsnNode): String? {
|
||||
}
|
||||
val previous = returnInsn.previous
|
||||
if (previous is MethodInsnNode) {
|
||||
if (NON_LOCAL_RETURN == previous.owner) {
|
||||
return previous.name
|
||||
val marker = previous
|
||||
if (NON_LOCAL_RETURN == marker.owner) {
|
||||
return marker.name
|
||||
}
|
||||
}
|
||||
return null
|
||||
@@ -456,12 +458,13 @@ private fun isInlineMarker(insn: AbstractInsnNode, name: String?): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
val methodInsnNode = insn
|
||||
return insn.getOpcode() == Opcodes.INVOKESTATIC &&
|
||||
insn.owner == INLINE_MARKER_CLASS_NAME &&
|
||||
methodInsnNode.owner == INLINE_MARKER_CLASS_NAME &&
|
||||
if (name != null)
|
||||
insn.name == name
|
||||
methodInsnNode.name == name
|
||||
else
|
||||
insn.name == INLINE_MARKER_BEFORE_METHOD_NAME || insn.name == INLINE_MARKER_AFTER_METHOD_NAME
|
||||
methodInsnNode.name == INLINE_MARKER_BEFORE_METHOD_NAME || methodInsnNode.name == INLINE_MARKER_AFTER_METHOD_NAME
|
||||
}
|
||||
|
||||
internal fun isBeforeInlineMarker(insn: AbstractInsnNode): Boolean {
|
||||
|
||||
@@ -40,7 +40,7 @@ private inline fun <reified T> arrayOf(vararg elements: T): Array<T> = elements
|
||||
|
||||
private inline fun <reified T> Array(size: Int, init: (Int) -> T): Array<T> {
|
||||
val result = arrayOfNulls<T>(size)
|
||||
for (i in result.indices) {
|
||||
for (i in 0..size - 1) {
|
||||
result[i] = init(i)
|
||||
}
|
||||
return result as Array<T>
|
||||
@@ -48,7 +48,7 @@ private inline fun <reified T> Array(size: Int, init: (Int) -> T): Array<T> {
|
||||
|
||||
private inline fun DoubleArray(size: Int, init: (Int) -> Double): DoubleArray {
|
||||
val result = DoubleArray(size)
|
||||
for (i in result.indices) {
|
||||
for (i in 0..size - 1) {
|
||||
result[i] = init(i)
|
||||
}
|
||||
return result
|
||||
@@ -56,7 +56,7 @@ private inline fun DoubleArray(size: Int, init: (Int) -> Double): DoubleArray {
|
||||
|
||||
private inline fun FloatArray(size: Int, init: (Int) -> Float): FloatArray {
|
||||
val result = FloatArray(size)
|
||||
for (i in result.indices) {
|
||||
for (i in 0..size - 1) {
|
||||
result[i] = init(i)
|
||||
}
|
||||
return result
|
||||
@@ -64,7 +64,7 @@ private inline fun FloatArray(size: Int, init: (Int) -> Float): FloatArray {
|
||||
|
||||
private inline fun LongArray(size: Int, init: (Int) -> Long): LongArray {
|
||||
val result = LongArray(size)
|
||||
for (i in result.indices) {
|
||||
for (i in 0..size - 1) {
|
||||
result[i] = init(i)
|
||||
}
|
||||
return result
|
||||
@@ -72,7 +72,7 @@ private inline fun LongArray(size: Int, init: (Int) -> Long): LongArray {
|
||||
|
||||
private inline fun IntArray(size: Int, init: (Int) -> Int): IntArray {
|
||||
val result = IntArray(size)
|
||||
for (i in result.indices) {
|
||||
for (i in 0..size - 1) {
|
||||
result[i] = init(i)
|
||||
}
|
||||
return result
|
||||
@@ -80,7 +80,7 @@ private inline fun IntArray(size: Int, init: (Int) -> Int): IntArray {
|
||||
|
||||
private inline fun CharArray(size: Int, init: (Int) -> Char): CharArray {
|
||||
val result = CharArray(size)
|
||||
for (i in result.indices) {
|
||||
for (i in 0..size - 1) {
|
||||
result[i] = init(i)
|
||||
}
|
||||
return result
|
||||
@@ -88,7 +88,7 @@ private inline fun CharArray(size: Int, init: (Int) -> Char): CharArray {
|
||||
|
||||
private inline fun ShortArray(size: Int, init: (Int) -> Short): ShortArray {
|
||||
val result = ShortArray(size)
|
||||
for (i in result.indices) {
|
||||
for (i in 0..size - 1) {
|
||||
result[i] = init(i)
|
||||
}
|
||||
return result
|
||||
@@ -96,7 +96,7 @@ private inline fun ShortArray(size: Int, init: (Int) -> Short): ShortArray {
|
||||
|
||||
private inline fun ByteArray(size: Int, init: (Int) -> Byte): ByteArray {
|
||||
val result = ByteArray(size)
|
||||
for (i in result.indices) {
|
||||
for (i in 0..size - 1) {
|
||||
result[i] = init(i)
|
||||
}
|
||||
return result
|
||||
@@ -104,7 +104,7 @@ private inline fun ByteArray(size: Int, init: (Int) -> Byte): ByteArray {
|
||||
|
||||
private inline fun BooleanArray(size: Int, init: (Int) -> Boolean): BooleanArray {
|
||||
val result = BooleanArray(size)
|
||||
for (i in result.indices) {
|
||||
for (i in 0..size - 1) {
|
||||
result[i] = init(i)
|
||||
}
|
||||
return result
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.codegen.CallableMethod
|
||||
class StringPlus : IntrinsicMethod() {
|
||||
override fun toCallable(method: CallableMethod): Callable =
|
||||
createIntrinsicCallable(method) {
|
||||
it.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "stringPlus",
|
||||
it.invokestatic("kotlin/jvm/internal/Intrinsics", "stringPlus",
|
||||
"(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;", false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,15 +232,17 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
|
||||
}
|
||||
|
||||
private fun findCleanInstructions(refValue: CapturedVarDescriptor, oldVarIndex: Int, instructions: InsnList): List<VarInsnNode> {
|
||||
return InsnSequence(instructions).filterIsInstance<VarInsnNode>().filter {
|
||||
it.opcode == Opcodes.ASTORE && it.`var` == oldVarIndex
|
||||
}.filter {
|
||||
it.previous?.opcode == Opcodes.ACONST_NULL
|
||||
}.filter {
|
||||
val operationIndex = instructions.indexOf(it)
|
||||
val localVariableNode = refValue.localVar!!
|
||||
instructions.indexOf(localVariableNode.start) < operationIndex && operationIndex < instructions.indexOf(localVariableNode.end)
|
||||
}.toList()
|
||||
val cleanInstructions =
|
||||
InsnSequence(instructions).filterIsInstance<VarInsnNode>().filter {
|
||||
it.opcode == Opcodes.ASTORE && it.`var` == oldVarIndex
|
||||
}.filter {
|
||||
it.previous?.opcode == Opcodes.ACONST_NULL
|
||||
}.filter {
|
||||
val operationIndex = instructions.indexOf(it)
|
||||
val localVariableNode = refValue.localVar!!
|
||||
instructions.indexOf(localVariableNode.start) < operationIndex && operationIndex < instructions.indexOf(localVariableNode.end)
|
||||
}.toList()
|
||||
return cleanInstructions
|
||||
}
|
||||
|
||||
private fun rewrite() {
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicVerifier
|
||||
|
||||
class MethodVerifier(private val checkPoint: String) : MethodTransformer() {
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
try {
|
||||
analyze(internalClassName, methodNode, BasicVerifier())
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
throw AssertionError("$checkPoint: incorrect bytecode", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
package org.jetbrains.kotlin.codegen.optimization
|
||||
|
||||
import org.jetbrains.kotlin.codegen.TransformationMethodVisitor
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.StackPeepholeOptimizationsTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.FastPopBackwardPropagationTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantBoxingMethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.PopBackwardPropagationTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.prepareForEmitting
|
||||
@@ -47,10 +47,7 @@ class OptimizationMethodVisitor(
|
||||
companion object {
|
||||
private val MEMORY_LIMIT_BY_METHOD_MB = 50
|
||||
|
||||
private val MANDATORY_METHOD_TRANSFORMER = CompositeMethodTransformer(
|
||||
FixStackWithLabelNormalizationMethodTransformer(),
|
||||
MethodVerifier("AFTER mandatory stack transformations")
|
||||
)
|
||||
private val MANDATORY_METHOD_TRANSFORMER = FixStackWithLabelNormalizationMethodTransformer()
|
||||
|
||||
private val OPTIMIZATION_TRANSFORMER = CompositeMethodTransformer(
|
||||
CapturedVarsOptimizationMethodTransformer(),
|
||||
@@ -58,12 +55,11 @@ class OptimizationMethodVisitor(
|
||||
RedundantCheckCastEliminationMethodTransformer(),
|
||||
ConstantConditionEliminationMethodTransformer(),
|
||||
RedundantBoxingMethodTransformer(),
|
||||
StackPeepholeOptimizationsTransformer(),
|
||||
FastPopBackwardPropagationTransformer(),
|
||||
PopBackwardPropagationTransformer(),
|
||||
DeadCodeEliminationMethodTransformer(),
|
||||
RedundantGotoMethodTransformer(),
|
||||
RedundantNopsCleanupMethodTransformer(),
|
||||
MethodVerifier("AFTER optimizations")
|
||||
RedundantNopsCleanupMethodTransformer()
|
||||
)
|
||||
|
||||
fun canBeOptimized(node: MethodNode): Boolean {
|
||||
|
||||
@@ -18,8 +18,8 @@ package org.jetbrains.kotlin.codegen.optimization.boxing
|
||||
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.RangeCodegenUtil
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
||||
import org.jetbrains.kotlin.codegen.isRangeOrProgression
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -213,7 +213,7 @@ fun AbstractInsnNode.isIteratorMethodCallOfProgression(values: List<BasicValue>)
|
||||
}
|
||||
|
||||
fun isProgressionClass(type: Type) =
|
||||
isRangeOrProgression(buildFqNameByInternal(type.internalName))
|
||||
RangeCodegenUtil.isRangeOrProgression(buildFqNameByInternal(type.internalName))
|
||||
|
||||
fun AbstractInsnNode.isAreEqualIntrinsicForSameTypedBoxedValues(values: List<BasicValue>) =
|
||||
isAreEqualIntrinsic() && areSameTypedBoxedValues(values)
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.boxing
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
class FastPopBackwardPropagationTransformer : MethodTransformer() {
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
while (transformOnce(methodNode)) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformOnce(methodNode: MethodNode): Boolean {
|
||||
val toRemove = ArrayList<AbstractInsnNode>()
|
||||
val toReplaceWithNop = ArrayList<AbstractInsnNode>()
|
||||
|
||||
val insns = methodNode.instructions.toArray()
|
||||
|
||||
for (i in 1 until insns.size) {
|
||||
val insn = insns[i]
|
||||
val prev = insns[i - 1]
|
||||
|
||||
when (insn.opcode) {
|
||||
Opcodes.POP -> {
|
||||
if (prev.isEliminatedByPop()) {
|
||||
toReplaceWithNop.add(insn)
|
||||
toRemove.add(prev)
|
||||
}
|
||||
}
|
||||
|
||||
Opcodes.POP2 -> {
|
||||
if (prev.isEliminatedByPop2()) {
|
||||
toReplaceWithNop.add(insn)
|
||||
toRemove.add(prev)
|
||||
}
|
||||
else if (i > 1) {
|
||||
val prev2 = insns[i - 2]
|
||||
if (prev.isEliminatedByPop() && prev2.isEliminatedByPop()) {
|
||||
toReplaceWithNop.add(insn)
|
||||
toRemove.add(prev)
|
||||
toRemove.add(prev2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toReplaceWithNop.forEach { methodNode.instructions.set(it, InsnNode(Opcodes.NOP)) }
|
||||
toRemove.forEach { methodNode.instructions.remove(it) }
|
||||
|
||||
return toReplaceWithNop.isNotEmpty() &&
|
||||
toRemove.isNotEmpty()
|
||||
}
|
||||
|
||||
private fun AbstractInsnNode.isEliminatedByPop() =
|
||||
opcode in Opcodes.ACONST_NULL..Opcodes.FCONST_2 ||
|
||||
opcode in Opcodes.BIPUSH..Opcodes.ILOAD ||
|
||||
opcode == Opcodes.FLOAD ||
|
||||
opcode == Opcodes.ALOAD ||
|
||||
isUnitInstance() ||
|
||||
opcode == Opcodes.DUP
|
||||
|
||||
private fun AbstractInsnNode.isEliminatedByPop2() =
|
||||
opcode == Opcodes.LCONST_0 || opcode == Opcodes.LCONST_1 ||
|
||||
opcode == Opcodes.DCONST_0 || opcode == Opcodes.DCONST_1 ||
|
||||
opcode == Opcodes.LLOAD ||
|
||||
opcode == Opcodes.DLOAD ||
|
||||
opcode == Opcodes.DUP2
|
||||
}
|
||||
|
||||
@@ -17,10 +17,8 @@
|
||||
package org.jetbrains.kotlin.codegen.optimization.boxing
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.OptimizationMethodVisitor
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.debugText
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.isLoadOperation
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.peekWords
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
||||
import org.jetbrains.kotlin.codegen.optimization.removeNodeGetNext
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
@@ -76,84 +74,46 @@ class PopBackwardPropagationTransformer : MethodTransformer() {
|
||||
postprocessNops()
|
||||
}
|
||||
|
||||
private fun analyzeMethodBody(): Array<out Frame<SourceValue>?> {
|
||||
val frames = Analyzer<SourceValue>(HazardsTrackingInterpreter()).analyze("fake", methodNode)
|
||||
|
||||
postprocessDupNxM(frames)
|
||||
|
||||
return frames
|
||||
}
|
||||
|
||||
private fun postprocessDupNxM(frames: Array<out Frame<SourceValue>?>) {
|
||||
val insns = methodNode.instructions.toArray()
|
||||
for (i in frames.indices) {
|
||||
val frame = frames[i] ?: continue
|
||||
val insn = insns[i]
|
||||
|
||||
when (insn.opcode) {
|
||||
Opcodes.DUP_X1 -> {
|
||||
val top2 = frame.peekWords(1, 1) ?: throwIncorrectBytecode(insn, frame)
|
||||
top2.forEach { it.insns.markAsDontTouch() }
|
||||
private fun analyzeMethodBody(): Array<out Frame<SourceValue>?> =
|
||||
Analyzer<SourceValue>(object : SourceInterpreter() {
|
||||
override fun naryOperation(insn: AbstractInsnNode, values: MutableList<out SourceValue>): SourceValue {
|
||||
for (value in values) {
|
||||
value.insns.markAsDontTouch()
|
||||
}
|
||||
return super.naryOperation(insn, values)
|
||||
}
|
||||
Opcodes.DUP2_X1 -> {
|
||||
val top3 = frame.peekWords(2, 1) ?: throwIncorrectBytecode(insn, frame)
|
||||
top3.forEach { it.insns.markAsDontTouch() }
|
||||
|
||||
override fun copyOperation(insn: AbstractInsnNode, value: SourceValue): SourceValue {
|
||||
value.insns.markAsDontTouch()
|
||||
return super.copyOperation(insn, value)
|
||||
}
|
||||
Opcodes.DUP_X2 -> {
|
||||
val top3 = frame.peekWords(1, 2) ?: throwIncorrectBytecode(insn, frame)
|
||||
top3.forEach { it.insns.markAsDontTouch() }
|
||||
|
||||
override fun unaryOperation(insn: AbstractInsnNode, value: SourceValue): SourceValue {
|
||||
if (insn.opcode != Opcodes.CHECKCAST && !insn.isPrimitiveTypeConversion()) {
|
||||
value.insns.markAsDontTouch()
|
||||
}
|
||||
return super.unaryOperation(insn, value)
|
||||
}
|
||||
Opcodes.DUP2_X2 -> {
|
||||
val top4 = frame.peekWords(2, 2) ?: throwIncorrectBytecode(insn, frame)
|
||||
top4.forEach { it.insns.markAsDontTouch() }
|
||||
|
||||
override fun binaryOperation(insn: AbstractInsnNode, value1: SourceValue, value2: SourceValue): SourceValue {
|
||||
value1.insns.markAsDontTouch()
|
||||
value2.insns.markAsDontTouch()
|
||||
return super.binaryOperation(insn, value1, value2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun throwIncorrectBytecode(insn: AbstractInsnNode?, frame: Frame<SourceValue>): Nothing {
|
||||
throw AssertionError("Incorrect bytecode at ${methodNode.instructions.indexOf(insn)}: ${insn.debugText} $frame")
|
||||
}
|
||||
override fun ternaryOperation(insn: AbstractInsnNode, value1: SourceValue, value2: SourceValue, value3: SourceValue): SourceValue {
|
||||
value1.insns.markAsDontTouch()
|
||||
value2.insns.markAsDontTouch()
|
||||
value3.insns.markAsDontTouch()
|
||||
return super.ternaryOperation(insn, value1, value2, value3)
|
||||
}
|
||||
|
||||
private inner class HazardsTrackingInterpreter : SourceInterpreter() {
|
||||
override fun naryOperation(insn: AbstractInsnNode, values: MutableList<out SourceValue>): SourceValue {
|
||||
for (value in values) {
|
||||
value.insns.markAsDontTouch()
|
||||
}
|
||||
return super.naryOperation(insn, values)
|
||||
}
|
||||
|
||||
override fun copyOperation(insn: AbstractInsnNode, value: SourceValue): SourceValue {
|
||||
value.insns.markAsDontTouch()
|
||||
return super.copyOperation(insn, value)
|
||||
}
|
||||
|
||||
override fun unaryOperation(insn: AbstractInsnNode, value: SourceValue): SourceValue {
|
||||
if (insn.opcode != Opcodes.CHECKCAST && !insn.isPrimitiveTypeConversion()) {
|
||||
value.insns.markAsDontTouch()
|
||||
}
|
||||
return super.unaryOperation(insn, value)
|
||||
}
|
||||
|
||||
override fun binaryOperation(insn: AbstractInsnNode, value1: SourceValue, value2: SourceValue): SourceValue {
|
||||
value1.insns.markAsDontTouch()
|
||||
value2.insns.markAsDontTouch()
|
||||
return super.binaryOperation(insn, value1, value2)
|
||||
}
|
||||
|
||||
override fun ternaryOperation(insn: AbstractInsnNode, value1: SourceValue, value2: SourceValue, value3: SourceValue): SourceValue {
|
||||
value1.insns.markAsDontTouch()
|
||||
value2.insns.markAsDontTouch()
|
||||
value3.insns.markAsDontTouch()
|
||||
return super.ternaryOperation(insn, value1, value2, value3)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Collection<AbstractInsnNode>.markAsDontTouch() {
|
||||
forEach {
|
||||
dontTouchInsnIndices[insnList.indexOf(it)] = true
|
||||
}
|
||||
}
|
||||
private fun Collection<AbstractInsnNode>.markAsDontTouch() {
|
||||
forEach {
|
||||
dontTouchInsnIndices[insnList.indexOf(it)] = true
|
||||
}
|
||||
}
|
||||
}).analyze("fake", methodNode)
|
||||
|
||||
|
||||
private fun computeTransformations() {
|
||||
|
||||
@@ -20,7 +20,7 @@ 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.RangeCodegenUtilKt;
|
||||
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;
|
||||
@@ -32,7 +32,7 @@ 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 : RangeCodegenUtilKt.getSupportedRangeTypes()) {
|
||||
for (PrimitiveType primitiveType : RangeCodegenUtil.supportedRangeTypes()) {
|
||||
builder.put(primitiveType.getTypeName().asString(), Type.getType(JvmPrimitiveType.get(primitiveType).getDesc()));
|
||||
}
|
||||
VALUES_TYPENAME_TO_TYPE = builder.build();
|
||||
@@ -41,7 +41,7 @@ public class ProgressionIteratorBasicValue extends StrictBasicValue {
|
||||
private static final ImmutableMap<PrimitiveType, ProgressionIteratorBasicValue> ITERATOR_VALUE_BY_ELEMENT_PRIMITIVE_TYPE;
|
||||
static {
|
||||
ImmutableMap.Builder<PrimitiveType, ProgressionIteratorBasicValue> builder = ImmutableMap.builder();
|
||||
for (PrimitiveType elementType : RangeCodegenUtilKt.getSupportedRangeTypes()) {
|
||||
for (PrimitiveType elementType : RangeCodegenUtil.supportedRangeTypes()) {
|
||||
builder.put(elementType, new ProgressionIteratorBasicValue(elementType.getTypeName().asString()));
|
||||
}
|
||||
ITERATOR_VALUE_BY_ELEMENT_PRIMITIVE_TYPE = builder.build();
|
||||
@@ -67,7 +67,7 @@ public class ProgressionIteratorBasicValue extends StrictBasicValue {
|
||||
@Nullable
|
||||
public static ProgressionIteratorBasicValue byProgressionClassType(@NotNull Type progressionClassType) {
|
||||
FqName classFqName = new FqName(progressionClassType.getClassName());
|
||||
PrimitiveType elementType = RangeCodegenUtilKt.getPrimitiveRangeOrProgressionElementType(classFqName);
|
||||
PrimitiveType elementType = RangeCodegenUtil.getPrimitiveRangeOrProgressionElementType(classFqName);
|
||||
return ITERATOR_VALUE_BY_ELEMENT_PRIMITIVE_TYPE.get(elementType);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
/*
|
||||
* 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.boxing
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.findPreviousOrNull
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnList
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
class StackPeepholeOptimizationsTransformer : MethodTransformer() {
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
while (transformOnce(methodNode)) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformOnce(methodNode: MethodNode): Boolean {
|
||||
val actions = ArrayList<(InsnList) -> Unit>()
|
||||
|
||||
val insns = methodNode.instructions.toArray()
|
||||
|
||||
forInsn@ for (i in 1 until insns.size) {
|
||||
val insn = insns[i]
|
||||
val prev = insn.previous
|
||||
val prevNonNop = insn.findPreviousOrNull { it.opcode != Opcodes.NOP } ?: continue@forInsn
|
||||
|
||||
when (insn.opcode) {
|
||||
Opcodes.POP -> {
|
||||
when {
|
||||
prevNonNop.isEliminatedByPop() -> actions.add {
|
||||
it.set(insn, InsnNode(Opcodes.NOP))
|
||||
it.remove(prevNonNop)
|
||||
}
|
||||
prevNonNop.opcode == Opcodes.DUP_X1 -> actions.add {
|
||||
it.remove(insn)
|
||||
it.set(prevNonNop, InsnNode(Opcodes.SWAP))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Opcodes.SWAP -> {
|
||||
val prevNonNop2 = prevNonNop.findPreviousOrNull { it.opcode != Opcodes.NOP } ?: continue@forInsn
|
||||
if (prevNonNop.isPurePushOfSize1() && prevNonNop2.isPurePushOfSize1()) {
|
||||
actions.add {
|
||||
it.remove(insn)
|
||||
it.set(prevNonNop, prevNonNop2.clone(emptyMap()))
|
||||
it.set(prevNonNop2, prevNonNop.clone(emptyMap()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Opcodes.I2L -> {
|
||||
when (prevNonNop.opcode) {
|
||||
Opcodes.ICONST_0 -> actions.add {
|
||||
it.remove(insn)
|
||||
it.set(prevNonNop, InsnNode(Opcodes.LCONST_0))
|
||||
}
|
||||
Opcodes.ICONST_1 -> actions.add {
|
||||
it.remove(insn)
|
||||
it.set(prevNonNop, InsnNode(Opcodes.LCONST_1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Opcodes.POP2 -> {
|
||||
if (prevNonNop.isEliminatedByPop2()) {
|
||||
actions.add {
|
||||
it.set(insn, InsnNode(Opcodes.NOP))
|
||||
it.remove(prevNonNop)
|
||||
}
|
||||
}
|
||||
else if (i > 1) {
|
||||
val prevNonNop2 = prevNonNop.findPreviousOrNull { it.opcode != Opcodes.NOP } ?: continue@forInsn
|
||||
if (prevNonNop.isEliminatedByPop() && prevNonNop2.isEliminatedByPop()) {
|
||||
actions.add {
|
||||
it.set(insn, InsnNode(Opcodes.NOP))
|
||||
it.remove(prevNonNop)
|
||||
it.remove(prevNonNop2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Opcodes.NOP ->
|
||||
if (prev.opcode == Opcodes.NOP) {
|
||||
actions.add {
|
||||
it.remove(prev)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actions.forEach { it(methodNode.instructions) }
|
||||
|
||||
return actions.isNotEmpty()
|
||||
}
|
||||
|
||||
private fun AbstractInsnNode.isEliminatedByPop() =
|
||||
isPurePushOfSize1() ||
|
||||
opcode == Opcodes.DUP
|
||||
|
||||
private fun AbstractInsnNode.isPurePushOfSize1(): Boolean =
|
||||
opcode in Opcodes.ACONST_NULL..Opcodes.FCONST_2 ||
|
||||
opcode in Opcodes.BIPUSH..Opcodes.ILOAD ||
|
||||
opcode == Opcodes.FLOAD ||
|
||||
opcode == Opcodes.ALOAD ||
|
||||
isUnitInstance()
|
||||
|
||||
private fun AbstractInsnNode.isEliminatedByPop2() =
|
||||
isPurePushOfSize2() ||
|
||||
opcode == Opcodes.DUP2
|
||||
|
||||
private fun AbstractInsnNode.isPurePushOfSize2(): Boolean =
|
||||
opcode == Opcodes.LCONST_0 || opcode == Opcodes.LCONST_1 ||
|
||||
opcode == Opcodes.DCONST_0 || opcode == Opcodes.DCONST_1 ||
|
||||
opcode == Opcodes.LLOAD ||
|
||||
opcode == Opcodes.DLOAD
|
||||
}
|
||||
|
||||
@@ -142,20 +142,20 @@ internal class FixStackAnalyzer(
|
||||
}
|
||||
|
||||
override fun pop(): BasicValue {
|
||||
return if (extraStack.isNotEmpty()) {
|
||||
extraStack.pop()
|
||||
if (extraStack.isNotEmpty()) {
|
||||
return extraStack.pop()
|
||||
}
|
||||
else {
|
||||
super.pop()
|
||||
return super.pop()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getStack(i: Int): BasicValue {
|
||||
return if (i < super.getMaxStackSize()) {
|
||||
super.getStack(i)
|
||||
if (i < super.getMaxStackSize()) {
|
||||
return super.getStack(i)
|
||||
}
|
||||
else {
|
||||
extraStack[i - maxStackSize]
|
||||
return extraStack[i - maxStackSize]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,31 +28,6 @@ fun <V : Value> Frame<V>.top(): V? =
|
||||
fun <V : Value> Frame<V>.peek(offset: Int): V? =
|
||||
if (stackSize > offset) getStack(stackSize - offset - 1) else null
|
||||
|
||||
private fun <V : Value> Frame<V>.peekWordsTo(dest: MutableList<V>, size: Int, offset0: Int = 0): Int {
|
||||
var offset = offset0
|
||||
var totalSize = 0
|
||||
while (totalSize < size) {
|
||||
val value = peek(offset++) ?: return -1
|
||||
dest.add(value)
|
||||
totalSize += value.size
|
||||
}
|
||||
if (totalSize > size) return -1
|
||||
return offset
|
||||
}
|
||||
|
||||
fun <V : Value> Frame<V>.peekWords(size: Int): List<V>? {
|
||||
val result = ArrayList<V>(size)
|
||||
return if (peekWordsTo(result, size) < 0) null else result
|
||||
}
|
||||
|
||||
fun <V : Value> Frame<V>.peekWords(size1: Int, size2: Int): List<V>? {
|
||||
val result = ArrayList<V>(size1 + size2)
|
||||
val offset = peekWordsTo(result, size1)
|
||||
if (offset < 0) return null
|
||||
if (peekWordsTo(result, size2, offset) < 0) return null
|
||||
return result
|
||||
}
|
||||
|
||||
class SavedStackDescriptor(
|
||||
val savedValues: List<BasicValue>,
|
||||
val firstLocalVarIndex: Int
|
||||
|
||||
@@ -44,13 +44,14 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
|
||||
private var changes = false
|
||||
|
||||
fun run(): Boolean {
|
||||
val checkedReferenceTypes = analyzeTypesAndRemoveDeadCode()
|
||||
eliminateRedundantChecks(checkedReferenceTypes)
|
||||
val stackOnThrowExceptions = hashMapOf<AbstractInsnNode, Int>()
|
||||
val checkedReferenceTypes = analyzeTypesAndRemoveDeadCode(stackOnThrowExceptions)
|
||||
eliminateRedundantChecks(checkedReferenceTypes, stackOnThrowExceptions)
|
||||
|
||||
return changes
|
||||
}
|
||||
|
||||
private fun analyzeTypesAndRemoveDeadCode(): Map<AbstractInsnNode, Type> {
|
||||
private fun analyzeTypesAndRemoveDeadCode(stackOnThrowExceptionsHolder: MutableMap<AbstractInsnNode, Int>): Map<AbstractInsnNode, Type> {
|
||||
val insns = methodNode.instructions.toArray()
|
||||
val frames = analyze(internalClassName, methodNode, OptimizationBasicInterpreter())
|
||||
|
||||
@@ -64,6 +65,9 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
|
||||
else if (insn.isCheckParameterIsNotNull() || insn.isCheckExpressionValueIsNotNull()) {
|
||||
checkedReferenceTypes[insn] = frame?.peek(1)?.type ?: continue
|
||||
}
|
||||
else if (insn.isThrowNpeIntrinsic()) {
|
||||
stackOnThrowExceptionsHolder[insn] = frame?.maxStackSize ?: continue
|
||||
}
|
||||
}
|
||||
|
||||
val dceResult = DeadCodeEliminationMethodTransformer().removeDeadCodeByFrames(methodNode, frames)
|
||||
@@ -74,8 +78,11 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
|
||||
return checkedReferenceTypes
|
||||
}
|
||||
|
||||
private fun eliminateRedundantChecks(checkedReferenceTypes: Map<AbstractInsnNode, Type>) {
|
||||
val nullabilityAssumptions = injectNullabilityAssumptions(checkedReferenceTypes)
|
||||
private fun eliminateRedundantChecks(
|
||||
checkedReferenceTypes: Map<AbstractInsnNode, Type>,
|
||||
stackOnThrowExceptions: MutableMap<AbstractInsnNode, Int>
|
||||
) {
|
||||
val nullabilityAssumptions = injectNullabilityAssumptions(checkedReferenceTypes, stackOnThrowExceptions)
|
||||
|
||||
val nullabilityMap = analyzeNullabilities()
|
||||
|
||||
@@ -84,8 +91,10 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
|
||||
transformTrivialChecks(nullabilityMap)
|
||||
}
|
||||
|
||||
private fun injectNullabilityAssumptions(checkedReferenceTypes: Map<AbstractInsnNode, Type>) =
|
||||
NullabilityAssumptionsBuilder(checkedReferenceTypes).injectNullabilityAssumptions()
|
||||
private fun injectNullabilityAssumptions(
|
||||
checkedReferenceTypes: Map<AbstractInsnNode, Type>,
|
||||
stackOnThrowExceptions: MutableMap<AbstractInsnNode, Int>
|
||||
) = NullabilityAssumptionsBuilder(checkedReferenceTypes, stackOnThrowExceptions).injectNullabilityAssumptions()
|
||||
|
||||
private fun analyzeNullabilities(): Map<AbstractInsnNode, StrictBasicValue> {
|
||||
val frames = analyze(internalClassName, methodNode, NullabilityInterpreter())
|
||||
@@ -168,7 +177,10 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
|
||||
}
|
||||
}
|
||||
|
||||
private inner class NullabilityAssumptionsBuilder(val checkedReferenceTypes: Map<AbstractInsnNode, Type>) {
|
||||
private inner class NullabilityAssumptionsBuilder(
|
||||
val checkedReferenceTypes: Map<AbstractInsnNode, Type>,
|
||||
val stackOnThrowExceptions: MutableMap<AbstractInsnNode, Int>
|
||||
) {
|
||||
|
||||
private val checksDependingOnVariable = HashMap<Int, MutableList<AbstractInsnNode>>()
|
||||
|
||||
@@ -362,6 +374,8 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
|
||||
athrow()
|
||||
})
|
||||
}
|
||||
|
||||
methodNode.maxStack = Math.max(methodNode.maxStack, (stackOnThrowExceptions[insn] ?: -1) + 1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
abstract class AbstractBoundedValue(
|
||||
protected val codegen: ExpressionCodegen,
|
||||
protected val rangeCall: ResolvedCall<out CallableDescriptor>,
|
||||
override val isLowInclusive: Boolean = true,
|
||||
override val isHighInclusive: Boolean = true
|
||||
) : BoundedValue {
|
||||
override val instanceType: Type = codegen.asmType(rangeCall.resultingDescriptor.returnType!!)
|
||||
|
||||
override fun putInstance(v: InstructionAdapter, type: Type) {
|
||||
codegen.invokeFunction(rangeCall.call, rangeCall, StackValue.none()).put(type, v)
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.generateCallReceiver
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.ForInArrayIndicesRangeLoopGenerator
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
class ArrayIndicesRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>): PrimitiveNumberRangeIntrinsicRangeValue(rangeCall) {
|
||||
private val expectedReceiverType: KotlinType = ExpressionCodegen.getExpectedReceiverType(rangeCall)
|
||||
|
||||
override fun getBoundedValue(codegen: ExpressionCodegen) =
|
||||
object : AbstractBoundedValue(codegen, rangeCall, isHighInclusive = false) {
|
||||
override fun putHighLow(v: InstructionAdapter, type: Type) {
|
||||
codegen.generateCallReceiver(rangeCall).put(codegen.asmType(expectedReceiverType), v)
|
||||
v.arraylength()
|
||||
StackValue.coerce(Type.INT_TYPE, type, v)
|
||||
|
||||
StackValue.constant(0, asmElementType).put(type, v)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||
ForInArrayIndicesRangeLoopGenerator(codegen, forExpression, rangeCall)
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.ForInArrayLoopGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.CallBasedInExpressionGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.InExpressionGenerator
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
|
||||
class ArrayRangeValue : RangeValue {
|
||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||
ForInArrayLoopGenerator(codegen, forExpression)
|
||||
|
||||
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
|
||||
CallBasedInExpressionGenerator(codegen, operatorReference)
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.range.comparison.getComparisonGeneratorForRangeContainsCall
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.CallBasedInExpressionGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.InExpressionGenerator
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
|
||||
abstract class CallIntrinsicRangeValue(protected val rangeCall: ResolvedCall<out CallableDescriptor>): RangeValue {
|
||||
protected abstract fun isIntrinsicInCall(resolvedCallForIn: ResolvedCall<out CallableDescriptor>): Boolean
|
||||
|
||||
protected abstract fun createIntrinsicInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression, resolvedCall: ResolvedCall<out CallableDescriptor>): InExpressionGenerator
|
||||
|
||||
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator {
|
||||
val resolvedCall = operatorReference.getResolvedCallWithAssert(codegen.bindingContext)
|
||||
return if (isIntrinsicInCall(resolvedCall))
|
||||
createIntrinsicInExpressionGenerator(codegen, operatorReference, resolvedCall)
|
||||
else
|
||||
CallBasedInExpressionGenerator(codegen, operatorReference)
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.generateCallReceiver
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.ForInCharSequenceIndicesRangeLoopGenerator
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
class CharSequenceIndicesRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>): PrimitiveNumberRangeIntrinsicRangeValue(rangeCall) {
|
||||
private val expectedReceiverType: KotlinType = ExpressionCodegen.getExpectedReceiverType(rangeCall)
|
||||
|
||||
override fun getBoundedValue(codegen: ExpressionCodegen) =
|
||||
object : AbstractBoundedValue(codegen, rangeCall, isHighInclusive = false) {
|
||||
override fun putHighLow(v: InstructionAdapter, type: Type) {
|
||||
codegen.generateCallReceiver(rangeCall).put(codegen.asmType(expectedReceiverType), v)
|
||||
v.invokeinterface("java/lang/CharSequence", "length", "()I")
|
||||
StackValue.coerce(Type.INT_TYPE, type, v)
|
||||
|
||||
StackValue.constant(0, asmElementType).put(type, v)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||
ForInCharSequenceIndicesRangeLoopGenerator(codegen, forExpression, rangeCall)
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.ForInCharSequenceLoopGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.CallBasedInExpressionGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.InExpressionGenerator
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
|
||||
class CharSequenceRangeValue : RangeValue {
|
||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||
ForInCharSequenceLoopGenerator(codegen, forExpression)
|
||||
|
||||
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
|
||||
CallBasedInExpressionGenerator(codegen, operatorReference)
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.generateCallReceiver
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.ForInCollectionIndicesRangeLoopGenerator
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
class CollectionIndicesRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>): PrimitiveNumberRangeIntrinsicRangeValue(rangeCall) {
|
||||
private val expectedReceiverType: KotlinType = ExpressionCodegen.getExpectedReceiverType(rangeCall)
|
||||
|
||||
override fun getBoundedValue(codegen: ExpressionCodegen) =
|
||||
object : AbstractBoundedValue(codegen, rangeCall, isHighInclusive = false) {
|
||||
override fun putHighLow(v: InstructionAdapter, type: Type) {
|
||||
codegen.generateCallReceiver(rangeCall).put(codegen.asmType(expectedReceiverType), v)
|
||||
v.invokeinterface("java/util/Collection", "size", "()I")
|
||||
StackValue.coerce(Type.INT_TYPE, type, v)
|
||||
|
||||
StackValue.constant(0, asmElementType).put(type, v)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||
ForInCollectionIndicesRangeLoopGenerator(codegen, forExpression, rangeCall)
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.isClosedRangeContains
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.IteratorForLoopGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.InContinuousRangeOfComparableExpressionGenerator
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
|
||||
class ComparableRangeLiteralRangeValue(
|
||||
codegen: ExpressionCodegen,
|
||||
rangeCall: ResolvedCall<out CallableDescriptor>
|
||||
) : CallIntrinsicRangeValue(rangeCall) {
|
||||
private val boundedValue = SimpleBoundedValue(codegen, rangeCall)
|
||||
|
||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||
IteratorForLoopGenerator(codegen, forExpression)
|
||||
|
||||
override fun isIntrinsicInCall(resolvedCallForIn: ResolvedCall<out CallableDescriptor>) =
|
||||
isClosedRangeContains(resolvedCallForIn.resultingDescriptor)
|
||||
|
||||
override fun createIntrinsicInExpressionGenerator(
|
||||
codegen: ExpressionCodegen,
|
||||
operatorReference: KtSimpleNameExpression,
|
||||
resolvedCall: ResolvedCall<out CallableDescriptor>
|
||||
) = InContinuousRangeOfComparableExpressionGenerator(operatorReference, boundedValue)
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.generateCallReceiver
|
||||
import org.jetbrains.kotlin.codegen.generateCallSingleArgument
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.ForInDownToProgressionLoopGenerator
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
|
||||
class DownToProgressionRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>): PrimitiveNumberRangeIntrinsicRangeValue(rangeCall) {
|
||||
override fun getBoundedValue(codegen: ExpressionCodegen) =
|
||||
SimpleBoundedValue(
|
||||
codegen, rangeCall,
|
||||
lowBound = codegen.generateCallSingleArgument(rangeCall),
|
||||
highBound = codegen.generateCallReceiver(rangeCall)
|
||||
)
|
||||
|
||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||
ForInDownToProgressionLoopGenerator(codegen, forExpression, rangeCall)
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.IteratorForLoopGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.CallBasedInExpressionGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.InExpressionGenerator
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
|
||||
class IterableRangeValue : RangeValue {
|
||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||
IteratorForLoopGenerator(codegen, forExpression)
|
||||
|
||||
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
|
||||
CallBasedInExpressionGenerator(codegen, operatorReference)
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.range.comparison.getComparisonGeneratorForRangeContainsCall
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.CallBasedInExpressionGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.InPrimitiveContinuousRangeExpressionGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.InExpressionGenerator
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
|
||||
abstract class PrimitiveNumberRangeIntrinsicRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(rangeCall) {
|
||||
protected val asmElementType = getAsmRangeElementTypeForPrimitiveRangeOrProgression(rangeCall.resultingDescriptor)
|
||||
|
||||
override fun isIntrinsicInCall(resolvedCallForIn: ResolvedCall<out CallableDescriptor>) =
|
||||
resolvedCallForIn.resultingDescriptor.let {
|
||||
isPrimitiveRangeContains(it) ||
|
||||
isClosedFloatingPointRangeContains(it) ||
|
||||
isPrimitiveNumberRangeExtensionContainsPrimitiveNumber(it)
|
||||
}
|
||||
|
||||
override fun createIntrinsicInExpressionGenerator(
|
||||
codegen: ExpressionCodegen,
|
||||
operatorReference: KtSimpleNameExpression,
|
||||
resolvedCall: ResolvedCall<out CallableDescriptor>
|
||||
): InExpressionGenerator {
|
||||
val comparisonGenerator = getComparisonGeneratorForRangeContainsCall(codegen, resolvedCall)
|
||||
return if (comparisonGenerator != null)
|
||||
InPrimitiveContinuousRangeExpressionGenerator(operatorReference, getBoundedValue(codegen), comparisonGenerator)
|
||||
else
|
||||
CallBasedInExpressionGenerator(codegen, operatorReference)
|
||||
}
|
||||
|
||||
protected abstract fun getBoundedValue(codegen: ExpressionCodegen): BoundedValue
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.ForInRangeLiteralLoopGenerator
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
|
||||
class PrimitiveNumberRangeLiteralRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>): PrimitiveNumberRangeIntrinsicRangeValue(rangeCall) {
|
||||
override fun getBoundedValue(codegen: ExpressionCodegen) =
|
||||
SimpleBoundedValue(codegen, rangeCall)
|
||||
|
||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||
ForInRangeLiteralLoopGenerator(codegen, forExpression, rangeCall)
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.ForInUntilRangeLoopGenerator
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
|
||||
class PrimitiveNumberUntilRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>): PrimitiveNumberRangeIntrinsicRangeValue(rangeCall) {
|
||||
override fun getBoundedValue(codegen: ExpressionCodegen) =
|
||||
SimpleBoundedValue(codegen, rangeCall, isLowInclusive = true, isHighInclusive = false)
|
||||
|
||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||
ForInUntilRangeLoopGenerator(codegen, forExpression, rangeCall)
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.ForInProgressionExpressionLoopGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.CallBasedInExpressionGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.InExpressionGenerator
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
|
||||
class PrimitiveProgressionRangeValue : RangeValue {
|
||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||
ForInProgressionExpressionLoopGenerator(codegen, forExpression)
|
||||
|
||||
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
|
||||
CallBasedInExpressionGenerator(codegen, operatorReference)
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.ForInRangeInstanceLoopGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.CallBasedInExpressionGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.InExpressionGenerator
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
|
||||
class PrimitiveRangeRangeValue : RangeValue {
|
||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||
ForInRangeInstanceLoopGenerator(codegen, forExpression)
|
||||
|
||||
override fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator =
|
||||
CallBasedInExpressionGenerator(codegen, operatorReference)
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.ForLoopGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.InExpressionGenerator
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
interface RangeValue {
|
||||
fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression): ForLoopGenerator
|
||||
|
||||
fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator
|
||||
}
|
||||
|
||||
|
||||
interface BoundedValue {
|
||||
val instanceType: Type
|
||||
|
||||
fun putInstance(v: InstructionAdapter, type: Type)
|
||||
|
||||
// It is necessary to maintain the proper evaluation order as of Kotlin 1.0 and 1.1
|
||||
// to evaluate range bounds left to right and put them on stack as 'high; low'.
|
||||
fun putHighLow(v: InstructionAdapter, type: Type)
|
||||
|
||||
val isLowInclusive: Boolean
|
||||
val isHighInclusive: Boolean
|
||||
}
|
||||
|
||||
fun BoundedValue.asStackValue(): StackValue =
|
||||
object : StackValue(instanceType) {
|
||||
override fun putSelector(type: Type, v: InstructionAdapter) {
|
||||
putInstance(v, type)
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
|
||||
fun ExpressionCodegen.createRangeValueForExpression(rangeExpression: KtExpression): RangeValue {
|
||||
// NB when you implement a new intrinsic RangeValue,
|
||||
// also look into org.jetbrains.kotlin.generators.tests and update related testData generators
|
||||
// (e.g., GenerateInRangeExpressionTestData).
|
||||
|
||||
getResolvedCallForRangeExpression(bindingContext, rangeExpression)?.let {
|
||||
createIntrinsifiedRangeValueOrNull(it)?.let {
|
||||
return it
|
||||
}
|
||||
}
|
||||
|
||||
val rangeType = bindingContext.getType(rangeExpression)!!
|
||||
val asmRangeType = asmType(rangeType)
|
||||
|
||||
return when {
|
||||
asmRangeType.sort == Type.ARRAY ->
|
||||
ArrayRangeValue()
|
||||
isPrimitiveRange(rangeType) ->
|
||||
PrimitiveRangeRangeValue()
|
||||
isPrimitiveProgression(rangeType) ->
|
||||
PrimitiveProgressionRangeValue()
|
||||
isSubtypeOfCharSequence(rangeType, state.module.builtIns) ->
|
||||
CharSequenceRangeValue()
|
||||
else ->
|
||||
IterableRangeValue()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSubtypeOfCharSequence(type: KotlinType, builtIns: KotlinBuiltIns) =
|
||||
KotlinTypeChecker.DEFAULT.isSubtypeOf(type, builtIns.getBuiltInClassByName(Name.identifier("CharSequence")).defaultType)
|
||||
|
||||
private fun getResolvedCallForRangeExpression(
|
||||
bindingContext: BindingContext,
|
||||
rangeExpression: KtExpression
|
||||
): ResolvedCall<out CallableDescriptor>? {
|
||||
val expression = KtPsiUtil.deparenthesize(rangeExpression) ?: return null
|
||||
|
||||
return when (expression) {
|
||||
is KtQualifiedExpression ->
|
||||
expression.selectorExpression.let { selector ->
|
||||
if (selector is KtCallExpression || selector is KtSimpleNameExpression)
|
||||
selector.getResolvedCall(bindingContext)
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
is KtSimpleNameExpression, is KtCallExpression ->
|
||||
expression.getResolvedCall(bindingContext)
|
||||
is KtBinaryExpression ->
|
||||
expression.operationReference.getResolvedCall(bindingContext)
|
||||
else ->
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun ExpressionCodegen.createIntrinsifiedRangeValueOrNull(rangeCall: ResolvedCall<out CallableDescriptor>): RangeValue? {
|
||||
val rangeCallee = rangeCall.resultingDescriptor
|
||||
|
||||
return when {
|
||||
isPrimitiveNumberRangeTo(rangeCallee) ->
|
||||
PrimitiveNumberRangeLiteralRangeValue(rangeCall)
|
||||
isPrimitiveNumberDownTo(rangeCallee) ->
|
||||
DownToProgressionRangeValue(rangeCall)
|
||||
isPrimitiveNumberUntil(rangeCallee) ->
|
||||
PrimitiveNumberUntilRangeValue(rangeCall)
|
||||
isArrayOrPrimitiveArrayIndices(rangeCallee) ->
|
||||
ArrayIndicesRangeValue(rangeCall)
|
||||
isCollectionIndices(rangeCallee) ->
|
||||
CollectionIndicesRangeValue(rangeCall)
|
||||
isCharSequenceIndices(rangeCallee) ->
|
||||
CharSequenceIndicesRangeValue(rangeCall)
|
||||
isComparableRangeTo(rangeCallee) ->
|
||||
ComparableRangeLiteralRangeValue(this, rangeCall)
|
||||
else ->
|
||||
null
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* 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.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
class SimpleBoundedValue(
|
||||
codegen: ExpressionCodegen,
|
||||
rangeCall: ResolvedCall<out CallableDescriptor>,
|
||||
private val lowBound: StackValue,
|
||||
isLowInclusive: Boolean,
|
||||
private val highBound: StackValue,
|
||||
isHighInclusive: Boolean
|
||||
): AbstractBoundedValue(codegen, rangeCall, isLowInclusive, isHighInclusive) {
|
||||
constructor(
|
||||
codegen: ExpressionCodegen,
|
||||
rangeCall: ResolvedCall<out CallableDescriptor>,
|
||||
isLowInclusive: Boolean = true,
|
||||
isHighInclusive: Boolean = true
|
||||
) : this(
|
||||
codegen,
|
||||
rangeCall,
|
||||
codegen.generateCallReceiver(rangeCall),
|
||||
isLowInclusive,
|
||||
codegen.generateCallSingleArgument(rangeCall),
|
||||
isHighInclusive
|
||||
)
|
||||
|
||||
constructor(
|
||||
codegen: ExpressionCodegen,
|
||||
rangeCall: ResolvedCall<out CallableDescriptor>,
|
||||
lowBound: StackValue,
|
||||
highBound: StackValue
|
||||
) : this(codegen, rangeCall, lowBound, true, highBound, true)
|
||||
|
||||
override fun putHighLow(v: InstructionAdapter, type: Type) {
|
||||
if (!lowBound.canHaveSideEffects() || !highBound.canHaveSideEffects()) {
|
||||
highBound.put(type, v)
|
||||
lowBound.put(type, v)
|
||||
}
|
||||
else {
|
||||
lowBound.put(type, v)
|
||||
highBound.put(type, v)
|
||||
AsmUtil.swap(v, type, type)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* 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.range.comparison
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.getRangeOrProgressionElementType
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
interface ComparisonGenerator {
|
||||
val comparedType: Type
|
||||
|
||||
fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label)
|
||||
fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label)
|
||||
fun jumpIfGreater(v: InstructionAdapter, label: Label)
|
||||
fun jumpIfLess(v: InstructionAdapter, label: Label)
|
||||
}
|
||||
|
||||
fun getComparisonGeneratorForPrimitiveType(type: Type): ComparisonGenerator =
|
||||
when {
|
||||
type.isRepresentedAsPrimitiveInt() -> IntComparisonGenerator
|
||||
type == Type.LONG_TYPE -> LongComparisonGenerator
|
||||
type == Type.FLOAT_TYPE -> FloatComparisonGenerator
|
||||
type == Type.DOUBLE_TYPE -> DoubleComparisonGenerator
|
||||
else -> throw UnsupportedOperationException("Unexpected primitive type: " + type)
|
||||
}
|
||||
|
||||
fun getComparisonGeneratorForRangeContainsCall(codegen: ExpressionCodegen, call: ResolvedCall<out CallableDescriptor>): ComparisonGenerator? {
|
||||
val descriptor = call.resultingDescriptor
|
||||
|
||||
val receiverType = descriptor.extensionReceiverParameter?.type ?: descriptor.dispatchReceiverParameter?.type ?: return null
|
||||
|
||||
val elementType = getRangeOrProgressionElementType(receiverType) ?: return null
|
||||
|
||||
val valueParameterType = descriptor.valueParameters.singleOrNull()?.type ?: return null
|
||||
|
||||
val asmElementType = codegen.asmType(elementType)
|
||||
val asmValueParameterType = codegen.asmType(valueParameterType)
|
||||
|
||||
return when {
|
||||
asmElementType == asmValueParameterType ->
|
||||
getComparisonGeneratorForPrimitiveType(asmElementType)
|
||||
|
||||
asmElementType.isRepresentedAsPrimitiveInt() && asmValueParameterType.isRepresentedAsPrimitiveInt() ->
|
||||
IntComparisonGenerator
|
||||
|
||||
asmElementType.isRepresentedAsPrimitiveInt() && asmValueParameterType == Type.LONG_TYPE ||
|
||||
asmValueParameterType.isRepresentedAsPrimitiveInt() && asmElementType == Type.LONG_TYPE ->
|
||||
LongComparisonGenerator
|
||||
|
||||
asmElementType == Type.FLOAT_TYPE && asmValueParameterType == Type.DOUBLE_TYPE ||
|
||||
asmElementType == Type.DOUBLE_TYPE && asmValueParameterType == Type.FLOAT_TYPE ->
|
||||
DoubleComparisonGenerator
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun Type.isRepresentedAsPrimitiveInt() =
|
||||
this == Type.INT_TYPE || this == Type.SHORT_TYPE || this == Type.BYTE_TYPE || this == Type.CHAR_TYPE
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* 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.range.comparison
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
sealed class FloatingPointComparisonGenerator(override val comparedType: Type): ComparisonGenerator {
|
||||
override fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) {
|
||||
v.cmpl(comparedType)
|
||||
v.ifge(label)
|
||||
}
|
||||
|
||||
override fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) {
|
||||
v.cmpg(comparedType)
|
||||
v.ifle(label)
|
||||
}
|
||||
|
||||
override fun jumpIfGreater(v: InstructionAdapter, label: Label) {
|
||||
v.cmpl(comparedType)
|
||||
v.ifgt(label)
|
||||
}
|
||||
|
||||
override fun jumpIfLess(v: InstructionAdapter, label: Label) {
|
||||
v.cmpg(comparedType)
|
||||
v.iflt(label)
|
||||
}
|
||||
}
|
||||
|
||||
object FloatComparisonGenerator : FloatingPointComparisonGenerator(Type.FLOAT_TYPE)
|
||||
|
||||
object DoubleComparisonGenerator : FloatingPointComparisonGenerator(Type.DOUBLE_TYPE)
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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.range.comparison
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
object IntComparisonGenerator : ComparisonGenerator {
|
||||
override val comparedType: Type = Type.INT_TYPE
|
||||
|
||||
override fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) {
|
||||
v.ificmpge(label)
|
||||
}
|
||||
|
||||
override fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) {
|
||||
v.ificmple(label)
|
||||
}
|
||||
|
||||
override fun jumpIfGreater(v: InstructionAdapter, label: Label) {
|
||||
v.ificmpgt(label)
|
||||
}
|
||||
|
||||
override fun jumpIfLess(v: InstructionAdapter, label: Label) {
|
||||
v.ificmplt(label)
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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.range.comparison
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
object LongComparisonGenerator : ComparisonGenerator {
|
||||
override val comparedType: Type = Type.LONG_TYPE
|
||||
|
||||
override fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) {
|
||||
v.lcmp()
|
||||
v.ifge(label)
|
||||
}
|
||||
|
||||
override fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) {
|
||||
v.lcmp()
|
||||
v.ifle(label)
|
||||
}
|
||||
|
||||
override fun jumpIfGreater(v: InstructionAdapter, label: Label) {
|
||||
v.lcmp()
|
||||
v.ifgt(label)
|
||||
}
|
||||
|
||||
override fun jumpIfLess(v: InstructionAdapter, label: Label) {
|
||||
v.lcmp()
|
||||
v.iflt(label)
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* 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.range.comparison
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
object ObjectComparisonGenerator : ComparisonGenerator {
|
||||
override val comparedType: Type = Type.getObjectType("java/lang/Comparable")
|
||||
|
||||
override fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) {
|
||||
invokeCompare(v)
|
||||
v.ifge(label)
|
||||
}
|
||||
|
||||
override fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) {
|
||||
invokeCompare(v)
|
||||
v.ifle(label)
|
||||
}
|
||||
|
||||
override fun jumpIfGreater(v: InstructionAdapter, label: Label) {
|
||||
invokeCompare(v)
|
||||
v.ifgt(label)
|
||||
}
|
||||
|
||||
override fun jumpIfLess(v: InstructionAdapter, label: Label) {
|
||||
invokeCompare(v)
|
||||
v.iflt(label)
|
||||
}
|
||||
|
||||
private fun invokeCompare(v: InstructionAdapter) {
|
||||
v.invokeinterface("java/lang/Comparable", "compareTo", "(Ljava/lang/Object;)I")
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* 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.range.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
|
||||
abstract class AbstractForInRangeWithGivenBoundsLoopGenerator(
|
||||
codegen: ExpressionCodegen,
|
||||
forExpression: KtForExpression,
|
||||
step: Int = 1
|
||||
) : AbstractForInRangeLoopGenerator(codegen, forExpression, step) {
|
||||
protected abstract fun generateFrom(): StackValue
|
||||
protected abstract fun generateTo(): StackValue
|
||||
|
||||
override fun storeRangeStartAndEnd() {
|
||||
loopParameter().store(generateFrom(), v)
|
||||
StackValue.local(endVar, asmElementType).store(generateTo(), v)
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* 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.range.forLoop
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
|
||||
class ForInProgressionExpressionLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression)
|
||||
: AbstractForInProgressionLoopGenerator(codegen, forExpression)
|
||||
{
|
||||
override fun storeProgressionParametersToLocalVars() {
|
||||
codegen.gen(forExpression.loopRange, asmLoopRangeType)
|
||||
v.dup()
|
||||
v.dup()
|
||||
|
||||
generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterType, loopParameterVar)
|
||||
generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, asmElementType, endVar)
|
||||
generateRangeOrProgressionProperty(asmLoopRangeType, "getStep", incrementType, incrementType, incrementVar)
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* 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.range.inExpression
|
||||
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
|
||||
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
|
||||
|
||||
class CallBasedInExpressionGenerator(
|
||||
val codegen: ExpressionCodegen,
|
||||
operatorReference: KtSimpleNameExpression
|
||||
) : InExpressionGenerator {
|
||||
private val resolvedCall = operatorReference.getResolvedCallWithAssert(codegen.bindingContext)
|
||||
private val isInverted = operatorReference.getReferencedNameElementType() == KtTokens.NOT_IN
|
||||
|
||||
override fun generate(argument: StackValue): BranchedValue =
|
||||
gen(argument).let { if (isInverted) Invert(it) else it }
|
||||
|
||||
private fun gen(argument: StackValue): BranchedValue =
|
||||
object : BranchedValue(argument, null, argument.type, Opcodes.IFEQ) {
|
||||
override fun putSelector(type: Type, v: InstructionAdapter) {
|
||||
invokeFunction(v)
|
||||
}
|
||||
|
||||
override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
|
||||
invokeFunction(v)
|
||||
v.visitJumpInsn(if (jumpIfFalse) Opcodes.IFEQ else Opcodes.IFNE, jumpLabel)
|
||||
}
|
||||
|
||||
private fun invokeFunction(v: InstructionAdapter) {
|
||||
val result = codegen.invokeFunction(resolvedCall.call, resolvedCall, none())
|
||||
result.put(result.type, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* 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.range.inExpression
|
||||
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.BranchedValue
|
||||
import org.jetbrains.kotlin.codegen.Invert
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.range.BoundedValue
|
||||
import org.jetbrains.kotlin.codegen.range.comparison.ObjectComparisonGenerator
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
class InContinuousRangeOfComparableExpressionGenerator(
|
||||
operatorReference: KtSimpleNameExpression,
|
||||
private val boundedValue: BoundedValue
|
||||
) : InExpressionGenerator {
|
||||
private val isNotIn = operatorReference.getReferencedNameElementType() == KtTokens.NOT_IN
|
||||
private val comparisonGenerator = ObjectComparisonGenerator
|
||||
|
||||
override fun generate(argument: StackValue): BranchedValue =
|
||||
gen(argument).let { if (isNotIn) Invert(it) else it }
|
||||
|
||||
private fun gen(argument: StackValue): BranchedValue =
|
||||
object : BranchedValue(argument, null, comparisonGenerator.comparedType, Opcodes.IFEQ) {
|
||||
override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
|
||||
if (jumpIfFalse) {
|
||||
genJumpIfFalse(v, jumpLabel)
|
||||
}
|
||||
else {
|
||||
genJumpIfTrue(v, jumpLabel)
|
||||
}
|
||||
}
|
||||
|
||||
private fun genJumpIfTrue(v: InstructionAdapter, jumpLabel: Label) {
|
||||
// if (arg is in range) goto jumpLabel
|
||||
|
||||
val exitLabel1 = Label()
|
||||
val exitLabel2 = Label()
|
||||
|
||||
boundedValue.putHighLow(v, operandType)
|
||||
arg1.put(operandType, v)
|
||||
AsmUtil.dupx(v, operandType)
|
||||
|
||||
// On stack: high arg low arg
|
||||
// if (low bound is NOT satisfied) goto exitLabel1
|
||||
if (boundedValue.isLowInclusive) {
|
||||
// arg < low
|
||||
v.swap()
|
||||
comparisonGenerator.jumpIfLess(v, exitLabel1)
|
||||
}
|
||||
else {
|
||||
// arg <= low
|
||||
v.swap()
|
||||
comparisonGenerator.jumpIfLessOrEqual(v, exitLabel1)
|
||||
}
|
||||
|
||||
// On stack: high arg
|
||||
// if (high bound is satisfied) goto jumpLabel
|
||||
if (boundedValue.isHighInclusive) {
|
||||
// arg <= high
|
||||
v.swap()
|
||||
comparisonGenerator.jumpIfLessOrEqual(v, jumpLabel)
|
||||
}
|
||||
else {
|
||||
// arg < high
|
||||
v.swap()
|
||||
comparisonGenerator.jumpIfLess(v, jumpLabel)
|
||||
}
|
||||
v.goTo(exitLabel2)
|
||||
|
||||
v.mark(exitLabel1)
|
||||
AsmUtil.pop2(v, operandType)
|
||||
|
||||
v.mark(exitLabel2)
|
||||
}
|
||||
|
||||
private fun genJumpIfFalse(v: InstructionAdapter, jumpLabel: Label) {
|
||||
// if (arg is NOT in range) goto jumpLabel
|
||||
|
||||
val cmpHighLabel = Label()
|
||||
|
||||
boundedValue.putHighLow(v, operandType)
|
||||
arg1.put(operandType, v)
|
||||
AsmUtil.dupx(v, operandType)
|
||||
|
||||
// On stack: high arg low arg
|
||||
// if ([low bound is satisfied]) goto cmpHighLabel
|
||||
if (boundedValue.isLowInclusive) {
|
||||
// arg >= low
|
||||
v.swap()
|
||||
comparisonGenerator.jumpIfGreaterOrEqual(v, cmpHighLabel)
|
||||
}
|
||||
else {
|
||||
// arg > low
|
||||
v.swap()
|
||||
comparisonGenerator.jumpIfGreater(v, cmpHighLabel)
|
||||
}
|
||||
|
||||
// Low bound is NOT satisfied, clear stack and goto jumpLabel
|
||||
AsmUtil.pop2(v, operandType)
|
||||
v.goTo(jumpLabel)
|
||||
|
||||
v.mark(cmpHighLabel)
|
||||
// On stack: high arg
|
||||
// if ([high bound is NOT satisfied]) goto jumpLabel
|
||||
if (boundedValue.isHighInclusive) {
|
||||
// arg > high
|
||||
v.swap()
|
||||
comparisonGenerator.jumpIfGreater(v, jumpLabel)
|
||||
}
|
||||
else {
|
||||
// arg >= high
|
||||
v.swap()
|
||||
comparisonGenerator.jumpIfGreaterOrEqual(v, jumpLabel)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
* 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.range.inExpression
|
||||
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.BranchedValue
|
||||
import org.jetbrains.kotlin.codegen.Invert
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.range.BoundedValue
|
||||
import org.jetbrains.kotlin.codegen.range.comparison.ComparisonGenerator
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
class InPrimitiveContinuousRangeExpressionGenerator(
|
||||
operatorReference: KtSimpleNameExpression,
|
||||
private val boundedValue: BoundedValue,
|
||||
private val comparisonGenerator: ComparisonGenerator
|
||||
) : InExpressionGenerator {
|
||||
private val isNotIn = operatorReference.getReferencedNameElementType() == KtTokens.NOT_IN
|
||||
|
||||
override fun generate(argument: StackValue): BranchedValue =
|
||||
gen(argument).let { if (isNotIn) Invert(it) else it }
|
||||
|
||||
private fun gen(argument: StackValue): BranchedValue =
|
||||
object : BranchedValue(argument, null, comparisonGenerator.comparedType, Opcodes.IFEQ) {
|
||||
override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) {
|
||||
if (jumpIfFalse) {
|
||||
genJumpIfFalse(v, jumpLabel)
|
||||
}
|
||||
else {
|
||||
genJumpIfTrue(v, jumpLabel)
|
||||
}
|
||||
}
|
||||
|
||||
private fun genJumpIfTrue(v: InstructionAdapter, jumpLabel: Label) {
|
||||
// if (arg is in range) goto jumpLabel
|
||||
|
||||
val exitLabel1 = Label()
|
||||
val exitLabel2 = Label()
|
||||
|
||||
boundedValue.putHighLow(v, operandType)
|
||||
arg1.put(operandType, v)
|
||||
AsmUtil.dupx(v, operandType)
|
||||
|
||||
// On stack: high arg low arg
|
||||
// if (low bound is NOT satisfied) goto exitLabel1
|
||||
if (boundedValue.isLowInclusive) {
|
||||
// low > arg
|
||||
comparisonGenerator.jumpIfGreater(v, exitLabel1)
|
||||
}
|
||||
else {
|
||||
// low >= arg
|
||||
comparisonGenerator.jumpIfGreaterOrEqual(v, exitLabel1)
|
||||
}
|
||||
|
||||
// On stack: high arg
|
||||
// if (high bound is satisfied) goto jumpLabel
|
||||
if (boundedValue.isHighInclusive) {
|
||||
// high >= arg
|
||||
comparisonGenerator.jumpIfGreaterOrEqual(v, jumpLabel)
|
||||
}
|
||||
else {
|
||||
// high > arg
|
||||
comparisonGenerator.jumpIfGreater(v, jumpLabel)
|
||||
}
|
||||
v.goTo(exitLabel2)
|
||||
|
||||
v.mark(exitLabel1)
|
||||
AsmUtil.pop2(v, operandType)
|
||||
|
||||
v.mark(exitLabel2)
|
||||
}
|
||||
|
||||
private fun genJumpIfFalse(v: InstructionAdapter, jumpLabel: Label) {
|
||||
// if (arg is NOT in range) goto jumpLabel
|
||||
|
||||
val cmpHighLabel = Label()
|
||||
|
||||
boundedValue.putHighLow(v, operandType)
|
||||
arg1.put(operandType, v)
|
||||
AsmUtil.dupx(v, operandType)
|
||||
|
||||
// On stack: high arg low arg
|
||||
// if ([low bound is satisfied]) goto cmpHighLabel
|
||||
if (boundedValue.isLowInclusive) {
|
||||
// low <= arg
|
||||
comparisonGenerator.jumpIfLessOrEqual(v, cmpHighLabel)
|
||||
}
|
||||
else {
|
||||
// low < arg
|
||||
comparisonGenerator.jumpIfLess(v, cmpHighLabel)
|
||||
}
|
||||
|
||||
// Low bound is NOT satisfied, clear stack and goto jumpLabel
|
||||
AsmUtil.pop2(v, operandType)
|
||||
v.goTo(jumpLabel)
|
||||
|
||||
v.mark(cmpHighLabel)
|
||||
// On stack: high arg
|
||||
// if ([high bound is NOT satisfied]) goto jumpLabel
|
||||
if (boundedValue.isHighInclusive) {
|
||||
// high < arg
|
||||
comparisonGenerator.jumpIfLess(v, jumpLabel)
|
||||
}
|
||||
else {
|
||||
// high <= arg
|
||||
comparisonGenerator.jumpIfLessOrEqual(v, jumpLabel)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.protobuf.GeneratedMessageLite;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.serialization.*;
|
||||
import org.jetbrains.kotlin.serialization.jvm.ClassMapperLite;
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf;
|
||||
@@ -85,7 +86,9 @@ public class JvmSerializerExtension extends SerializerExtension {
|
||||
proto.setExtension(JvmProtoBuf.classModuleName, stringTable.getStringIndex(moduleName));
|
||||
}
|
||||
|
||||
writeLocalProperties(proto, typeMapper.mapClass(descriptor), JvmProtoBuf.classLocalVariable);
|
||||
Type containerAsmType =
|
||||
DescriptorUtils.isInterface(descriptor) ? typeMapper.mapDefaultImpls(descriptor) : typeMapper.mapClass(descriptor);
|
||||
writeLocalProperties(proto, containerAsmType, JvmProtoBuf.classLocalVariable);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -99,20 +99,6 @@ public class KotlinTypeMapper {
|
||||
private final boolean isJvm8TargetWithDefaults;
|
||||
|
||||
private final TypeMappingConfiguration<Type> typeMappingConfiguration = new TypeMappingConfiguration<Type>() {
|
||||
private final Function2<String, String, String> defaultClassNameFactory
|
||||
= TypeMappingConfiguration.Companion.getDEFAULT_INNER_CLASS_NAME_FACTORY();
|
||||
|
||||
private final Function2<String, String, String> innerClassNameFactory = new Function2<String, String, String>() {
|
||||
@Override
|
||||
public String invoke(String outer, String inner) {
|
||||
if (classBuilderMode == ClassBuilderMode.KAPT3) {
|
||||
return outer + '/' + inner;
|
||||
}
|
||||
|
||||
return defaultClassNameFactory.invoke(outer, inner);
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public KotlinType commonSupertype(@NotNull Collection<KotlinType> types) {
|
||||
@@ -122,7 +108,7 @@ public class KotlinTypeMapper {
|
||||
@NotNull
|
||||
@Override
|
||||
public Function2<String, String, String> getInnerClassNameFactory() {
|
||||
return innerClassNameFactory;
|
||||
return TypeMappingConfiguration.DefaultImpls.getInnerClassNameFactory(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
|
||||
enum class FieldAccessorKind(val suffix: String) {
|
||||
NORMAL("p"),
|
||||
@@ -27,18 +26,15 @@ enum class FieldAccessorKind(val suffix: String) {
|
||||
override fun toString() = suffix
|
||||
}
|
||||
|
||||
private fun CallableMemberDescriptor.getJvmName() =
|
||||
DescriptorUtils.getJvmName(this) ?: name.asString()
|
||||
|
||||
fun getAccessorNameSuffix(descriptor: CallableMemberDescriptor, superCallDescriptor: ClassDescriptor?,
|
||||
accessorKind: FieldAccessorKind): String {
|
||||
val suffix = when (descriptor) {
|
||||
is ConstructorDescriptor ->
|
||||
return "will be ignored"
|
||||
is SimpleFunctionDescriptor ->
|
||||
descriptor.getJvmName()
|
||||
descriptor.name.asString()
|
||||
is PropertyDescriptor ->
|
||||
descriptor.getJvmName() + "$" + accessorKind
|
||||
descriptor.name.asString() + "$" + accessorKind
|
||||
else ->
|
||||
throw UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.cli.common.arguments;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.config.AnalysisFlag;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public abstract class CommonCompilerArguments extends CommonToolArguments {
|
||||
public static final long serialVersionUID = 0L;
|
||||
|
||||
@@ -89,6 +96,14 @@ public abstract class CommonCompilerArguments extends CommonToolArguments {
|
||||
public static final String ERROR = "error";
|
||||
public static final String ENABLE = "enable";
|
||||
|
||||
@NotNull
|
||||
public Map<AnalysisFlag<?>, Object> configureAnalysisFlags() {
|
||||
Map<AnalysisFlag<?>, Object> result = new HashMap<>();
|
||||
result.put(AnalysisFlag.getSkipMetadataVersionCheck(), skipMetadataVersionCheck);
|
||||
result.put(AnalysisFlag.getMultiPlatformDoNotCheckImpl(), noCheckImpl);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Used only for serialize and deserialize settings. Don't use in other places!
|
||||
public static final class DummyImpl extends CommonCompilerArguments {}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user