mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-24 08:31:30 +00:00
Compare commits
304 Commits
show_all_e
...
androidxml
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15dbfa7184 | ||
|
|
b0196ac1ad | ||
|
|
0e07cb9872 | ||
|
|
0c6622489b | ||
|
|
a4bbf9b3ec | ||
|
|
bb0141b85f | ||
|
|
abc17943d7 | ||
|
|
5f209d4351 | ||
|
|
a1989dc5e0 | ||
|
|
da32f47d2a | ||
|
|
78b3613cf5 | ||
|
|
eae40ab965 | ||
|
|
18ff58e4e7 | ||
|
|
2d6ec5bd5d | ||
|
|
50ec0d7f8d | ||
|
|
01b22a1dd1 | ||
|
|
73c2db8f44 | ||
|
|
84690dd9ee | ||
|
|
7402cf8356 | ||
|
|
5a3186a7f8 | ||
|
|
9e75390895 | ||
|
|
0c180275f1 | ||
|
|
06d173ca44 | ||
|
|
f8dcbd8477 | ||
|
|
cc6a9d5183 | ||
|
|
67a3932615 | ||
|
|
b934402b55 | ||
|
|
1e25af94c0 | ||
|
|
ab7177e251 | ||
|
|
52e0bf88f7 | ||
|
|
bbd4cb93ed | ||
|
|
4866168a21 | ||
|
|
fd125e07b6 | ||
|
|
74b1017fcf | ||
|
|
c3a668c8ca | ||
|
|
f20731548d | ||
|
|
b9b3575eb4 | ||
|
|
28b8c8b5d6 | ||
|
|
8eba35cd76 | ||
|
|
530d6caa47 | ||
|
|
6211485143 | ||
|
|
82cfb218e0 | ||
|
|
9deea1caad | ||
|
|
ca701f40e9 | ||
|
|
e92f26123f | ||
|
|
785a2d4200 | ||
|
|
6554258166 | ||
|
|
7a06c8176e | ||
|
|
f582159d72 | ||
|
|
a84b3e82e6 | ||
|
|
7834423136 | ||
|
|
aef7523b79 | ||
|
|
b516cdffa8 | ||
|
|
7857302c47 | ||
|
|
b6bc9a92d6 | ||
|
|
ffd3d1ffa3 | ||
|
|
a18c97e6c5 | ||
|
|
89908524ab | ||
|
|
f3875cfde6 | ||
|
|
c5d412e496 | ||
|
|
c5689f5c26 | ||
|
|
70253a61b6 | ||
|
|
6e7c27d9fd | ||
|
|
5a994db798 | ||
|
|
d959d4dbd0 | ||
|
|
7a8bbccda3 | ||
|
|
795177ca80 | ||
|
|
8a191bb1a2 | ||
|
|
b7308b9b7c | ||
|
|
cc31520089 | ||
|
|
80547cf292 | ||
|
|
2a0a03e011 | ||
|
|
ffbe0a3e4e | ||
|
|
8a7bc4fa71 | ||
|
|
a682a1d208 | ||
|
|
d955cc87dc | ||
|
|
cb1da3b07b | ||
|
|
e2ef7efcb4 | ||
|
|
ee46064f02 | ||
|
|
770a732449 | ||
|
|
03732ac606 | ||
|
|
9683bc385a | ||
|
|
e35cb603f9 | ||
|
|
71edc602c8 | ||
|
|
958ea49978 | ||
|
|
86b2a3e5a5 | ||
|
|
de56576d15 | ||
|
|
a5d1936393 | ||
|
|
c63281f91a | ||
|
|
f4c83d88eb | ||
|
|
4ca39e8f9a | ||
|
|
e85d34b445 | ||
|
|
e9b16f3e1b | ||
|
|
854962a139 | ||
|
|
a6ba3a569d | ||
|
|
0f43d4d07c | ||
|
|
be211d7cda | ||
|
|
9032a6166e | ||
|
|
35ebbab733 | ||
|
|
267aabae12 | ||
|
|
a04efad059 | ||
|
|
6179b4889b | ||
|
|
4994e771d0 | ||
|
|
8ad18df3fa | ||
|
|
e1c7ad50d6 | ||
|
|
0af291091e | ||
|
|
b70466f9f3 | ||
|
|
ed14f86957 | ||
|
|
3424142b65 | ||
|
|
f8968c2f77 | ||
|
|
916cfb7051 | ||
|
|
2352085391 | ||
|
|
098b4c170f | ||
|
|
f1d9d11590 | ||
|
|
469db95662 | ||
|
|
e035fc3219 | ||
|
|
b79b7554ff | ||
|
|
89f0c8dc87 | ||
|
|
0a97469ff4 | ||
|
|
ff29e581db | ||
|
|
afd8809ff5 | ||
|
|
6043c6d0a7 | ||
|
|
22e3557895 | ||
|
|
67df2b448f | ||
|
|
cf59af6c7a | ||
|
|
0582cf5db1 | ||
|
|
ae69bea543 | ||
|
|
d9318fdc57 | ||
|
|
06ab4e1c9a | ||
|
|
2c3f0f8c29 | ||
|
|
8ec2b5a973 | ||
|
|
5d7a07456d | ||
|
|
34632f46f6 | ||
|
|
d1e43d6482 | ||
|
|
08e3a6a9de | ||
|
|
9573c739ea | ||
|
|
23ea43fde5 | ||
|
|
9d49089041 | ||
|
|
6aff9803c4 | ||
|
|
2e4e5c5d1d | ||
|
|
dca6e31519 | ||
|
|
d1d722546e | ||
|
|
f42d7319a5 | ||
|
|
1239d37cb9 | ||
|
|
54799b1a34 | ||
|
|
cd0551078c | ||
|
|
19497262b3 | ||
|
|
2227b87ca3 | ||
|
|
ec7d294fcc | ||
|
|
477378fab7 | ||
|
|
f292c554cb | ||
|
|
9219616bb8 | ||
|
|
4370577457 | ||
|
|
649a6f12bb | ||
|
|
6127af97a5 | ||
|
|
b3e075173b | ||
|
|
bf368b2bc2 | ||
|
|
028520956f | ||
|
|
da159c1e53 | ||
|
|
e1c2fbaec0 | ||
|
|
35cda83c8f | ||
|
|
96308aa14e | ||
|
|
80a7c64369 | ||
|
|
e2273a3d85 | ||
|
|
43c26d0947 | ||
|
|
8f92141137 | ||
|
|
49e5b950ce | ||
|
|
b5832d2656 | ||
|
|
9f7979d0ce | ||
|
|
4d055d5ab4 | ||
|
|
c30aa7db84 | ||
|
|
7b374b9509 | ||
|
|
7d6da551d1 | ||
|
|
4194f1c418 | ||
|
|
2ba9856a85 | ||
|
|
806d79caba | ||
|
|
4cb9fbc026 | ||
|
|
232ab0b065 | ||
|
|
d4a845da01 | ||
|
|
c1125402bd | ||
|
|
c57441b51b | ||
|
|
e3876624d8 | ||
|
|
fabdc1fd32 | ||
|
|
350d446031 | ||
|
|
7616d3e18a | ||
|
|
7c61c36746 | ||
|
|
4cdcadef9f | ||
|
|
ea8977c5b5 | ||
|
|
3e4cc87c87 | ||
|
|
c5c1ecf6c0 | ||
|
|
5a5c4145f2 | ||
|
|
e91e724469 | ||
|
|
ef60a7f776 | ||
|
|
878ebb9575 | ||
|
|
d44926ffde | ||
|
|
e53aca5496 | ||
|
|
de6a5dd6dc | ||
|
|
6e7e13d320 | ||
|
|
b4909cc849 | ||
|
|
0462d152eb | ||
|
|
56978c4e16 | ||
|
|
7d6542854b | ||
|
|
f4924299dd | ||
|
|
19fb090f28 | ||
|
|
e6ea0537c8 | ||
|
|
afbd1aeffc | ||
|
|
93d8791df1 | ||
|
|
3fcf0f7340 | ||
|
|
94c9338e3c | ||
|
|
e30998d3c1 | ||
|
|
7df65d595c | ||
|
|
2bb553612c | ||
|
|
9961a5ff16 | ||
|
|
16809bc1c6 | ||
|
|
427b3c80bc | ||
|
|
f43a9968ba | ||
|
|
726f49b3f8 | ||
|
|
34aada75eb | ||
|
|
6ed57f5e7a | ||
|
|
86d598677d | ||
|
|
0dfc793a45 | ||
|
|
7de406991a | ||
|
|
e32f307960 | ||
|
|
c074b4317e | ||
|
|
3ab1901f06 | ||
|
|
7b77229638 | ||
|
|
a6d2624807 | ||
|
|
f2b9b370e1 | ||
|
|
cde74504d4 | ||
|
|
cb58d19e29 | ||
|
|
060796997e | ||
|
|
f9b33c4137 | ||
|
|
b435904d7f | ||
|
|
9af1c3e4dc | ||
|
|
36b50a25f9 | ||
|
|
78cde5c740 | ||
|
|
4ed744428b | ||
|
|
081d2cf95c | ||
|
|
c4bfa0edca | ||
|
|
9e38d207f2 | ||
|
|
187a3f0b9f | ||
|
|
8a5239f794 | ||
|
|
8a44325327 | ||
|
|
8d89ac897a | ||
|
|
68201c3e86 | ||
|
|
5847c3559b | ||
|
|
bf546c83fb | ||
|
|
fe136b500a | ||
|
|
67c9a2323c | ||
|
|
8368689af8 | ||
|
|
faa9f4bb14 | ||
|
|
c0657320f5 | ||
|
|
ec02734a30 | ||
|
|
563119ffc7 | ||
|
|
bb87377457 | ||
|
|
e6a17cbd78 | ||
|
|
bdca7e0e37 | ||
|
|
1d71016097 | ||
|
|
07a4d0e77e | ||
|
|
32f391aa51 | ||
|
|
a48fbacbd9 | ||
|
|
da004cf104 | ||
|
|
735fd6c626 | ||
|
|
b14e979d70 | ||
|
|
2b388ed308 | ||
|
|
b5f738db07 | ||
|
|
f178356bf0 | ||
|
|
f5ee68064f | ||
|
|
432ec31daf | ||
|
|
9564eaa6fd | ||
|
|
309329afd0 | ||
|
|
90c09762e3 | ||
|
|
5a0b786cb9 | ||
|
|
40761dfc4c | ||
|
|
6a76ca1066 | ||
|
|
98eed5cb0e | ||
|
|
04bb43e907 | ||
|
|
bf7a295ace | ||
|
|
2ae1286515 | ||
|
|
fbd09911f3 | ||
|
|
e796f88b38 | ||
|
|
de61456725 | ||
|
|
2a9005b466 | ||
|
|
853def0a10 | ||
|
|
040d1693e8 | ||
|
|
1b60f39959 | ||
|
|
741e5f61e9 | ||
|
|
03e2b4d516 | ||
|
|
07a257b1fe | ||
|
|
855ed81c11 | ||
|
|
f1c18d0e3f | ||
|
|
a3758f9fa3 | ||
|
|
c0a8e8a4fc | ||
|
|
9434114c45 | ||
|
|
483232a3e5 | ||
|
|
af01c0ff94 | ||
|
|
08c3bb35b2 | ||
|
|
92e962eced | ||
|
|
88a2612348 | ||
|
|
3dcfae4a81 | ||
|
|
655682ac97 | ||
|
|
d5f509580f | ||
|
|
a4613ec4a0 | ||
|
|
75f7f296aa |
2
.idea/ant.xml
generated
2
.idea/ant.xml
generated
@@ -4,7 +4,7 @@
|
||||
<buildFile url="file://$PROJECT_DIR$/grammar/buildGrammarLexer.xml" />
|
||||
<buildFile url="file://$PROJECT_DIR$/compiler/frontend/buildLexer.xml" />
|
||||
<buildFile url="file://$PROJECT_DIR$/build.xml">
|
||||
<maximumHeapSize value="512" />
|
||||
<maximumHeapSize value="1024" />
|
||||
</buildFile>
|
||||
<buildFile url="file://$PROJECT_DIR$/update_dependencies.xml" />
|
||||
<buildFile url="file://$PROJECT_DIR$/TeamCityBuild.xml">
|
||||
|
||||
18
.idea/artifacts/KotlinAndroidExtensionsPlugin.xml
generated
Normal file
18
.idea/artifacts/KotlinAndroidExtensionsPlugin.xml
generated
Normal file
@@ -0,0 +1,18 @@
|
||||
<component name="ArtifactManager">
|
||||
<artifact name="KotlinAndroidExtensionsPlugin">
|
||||
<output-path>$PROJECT_DIR$/out/artifacts/KotlinAndroidExtensionsPlugin</output-path>
|
||||
<root id="root">
|
||||
<element id="directory" name="lib">
|
||||
<element id="archive" name="kotlin-android-extensions-plugin.jar">
|
||||
<element id="module-output" name="android-compiler-plugin" />
|
||||
<element id="module-output" name="android-idea-plugin" />
|
||||
</element>
|
||||
<element id="directory" name="jps">
|
||||
<element id="archive" name="kotlin-android-extensions-jps.jar">
|
||||
<element id="module-output" name="android-jps-plugin" />
|
||||
</element>
|
||||
</element>
|
||||
</element>
|
||||
</root>
|
||||
</artifact>
|
||||
</component>
|
||||
2
.idea/artifacts/KotlinPlugin.xml
generated
2
.idea/artifacts/KotlinPlugin.xml
generated
@@ -31,6 +31,8 @@
|
||||
<element id="module-output" name="eval4j" />
|
||||
<element id="module-output" name="idea-analysis" />
|
||||
<element id="module-output" name="ide-lazy-resolve" />
|
||||
<element id="module-output" name="android-compiler-plugin" />
|
||||
<element id="module-output" name="android-idea-plugin" />
|
||||
</element>
|
||||
<element id="library" level="project" name="javax.inject" />
|
||||
<element id="directory" name="jps">
|
||||
|
||||
6
.idea/dictionaries/Nikolay_Krasko.xml
generated
6
.idea/dictionaries/Nikolay_Krasko.xml
generated
@@ -3,9 +3,15 @@
|
||||
<words>
|
||||
<w>accessors</w>
|
||||
<w>goto</w>
|
||||
<w>gradle</w>
|
||||
<w>kdoc</w>
|
||||
<w>kompiler</w>
|
||||
<w>memoize</w>
|
||||
<w>memoized</w>
|
||||
<w>multiline</w>
|
||||
<w>preload</w>
|
||||
<w>preloader</w>
|
||||
<w>preloading</w>
|
||||
<w>preprocess</w>
|
||||
<w>redeclarations</w>
|
||||
<w>subclassed</w>
|
||||
|
||||
38
.idea/libraries/android.xml
generated
Normal file
38
.idea/libraries/android.xml
generated
Normal file
@@ -0,0 +1,38 @@
|
||||
<component name="libraryTable">
|
||||
<library name="android">
|
||||
<ANNOTATIONS>
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/android-src.zip!/" />
|
||||
</ANNOTATIONS>
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/lib/android.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/lib/jps/android-jps-plugin.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/lib/android-common.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/lib/jps/android-gradle-jps.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/lib/manifest-merger.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/lib/builder-model-0.12.0.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/lib/commons-compress-1.0.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/lib/layoutlib-api.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/lib/common.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/lib/sdklib.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/lib/resources_en.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/lib/sdk-tools.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/lib/jarutils.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/lib/android-rt.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/android-src.zip!/rt/src" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/android-src.zip!/gen" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/android-src.zip!/src" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/android-src.zip!/common/src" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/android-src.zip!/common/testSrc" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/android-src.zip!/testSrc" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/android-src.zip!/ultimate/src" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/android-src.zip!/guiTestSrc" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/android-src.zip!/jps-plugin/src" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/android-src.zip!/jps-plugin/testSrc" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/android-src.zip!/android-gradle-jps/src" />
|
||||
<root url="jar://$PROJECT_DIR$/ideaSDK/plugins/android/android-src.zip!/android-gradle-jps/testSrc" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
9
.idea/libraries/android_tests.xml
generated
Normal file
9
.idea/libraries/android_tests.xml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<component name="libraryTable">
|
||||
<library name="android_tests">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/android_tests.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
4
.idea/modules.xml
generated
4
.idea/modules.xml
generated
@@ -3,6 +3,9 @@
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/Kotlin.iml" filepath="$PROJECT_DIR$/Kotlin.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/android-compiler-plugin/android-compiler-plugin.iml" filepath="$PROJECT_DIR$/plugins/android-compiler-plugin/android-compiler-plugin.iml" group="plugins" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/android-idea-plugin/android-idea-plugin.iml" filepath="$PROJECT_DIR$/plugins/android-idea-plugin/android-idea-plugin.iml" group="plugins" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/android-jps-plugin/android-jps-plugin.iml" filepath="$PROJECT_DIR$/plugins/android-jps-plugin/android-jps-plugin.iml" group="plugins" />
|
||||
<module fileurl="file://$PROJECT_DIR$/android-studio/android-studio.iml" filepath="$PROJECT_DIR$/android-studio/android-studio.iml" group="ide" />
|
||||
<module fileurl="file://$PROJECT_DIR$/compiler/android-tests/android-tests.iml" filepath="$PROJECT_DIR$/compiler/android-tests/android-tests.iml" group="compiler" />
|
||||
<module fileurl="file://$PROJECT_DIR$/compiler/backend/backend.iml" filepath="$PROJECT_DIR$/compiler/backend/backend.iml" group="compiler/java" />
|
||||
@@ -37,6 +40,7 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/js/js.tests/js.tests.iml" filepath="$PROJECT_DIR$/js/js.tests/js.tests.iml" group="compiler/js" />
|
||||
<module fileurl="file://$PROJECT_DIR$/js/js.translator/js.translator.iml" filepath="$PROJECT_DIR$/js/js.translator/js.translator.iml" group="compiler/js" />
|
||||
<module fileurl="file://$PROJECT_DIR$/jps-plugin/kannotator-jps-plugin-test/kannotator-jps-plugin-test.iml" filepath="$PROJECT_DIR$/jps-plugin/kannotator-jps-plugin-test/kannotator-jps-plugin-test.iml" group="ide/jps" />
|
||||
<module fileurl="file://$PROJECT_DIR$/compiler/plugin-api/plugin-api.iml" filepath="$PROJECT_DIR$/compiler/plugin-api/plugin-api.iml" group="compiler" />
|
||||
<module fileurl="file://$PROJECT_DIR$/compiler/preloader/preloader.iml" filepath="$PROJECT_DIR$/compiler/preloader/preloader.iml" group="compiler/cli" />
|
||||
<module fileurl="file://$PROJECT_DIR$/core/reflection/reflection.iml" filepath="$PROJECT_DIR$/core/reflection/reflection.iml" group="core" />
|
||||
<module fileurl="file://$PROJECT_DIR$/core/runtime.jvm/runtime.jvm.iml" filepath="$PROJECT_DIR$/core/runtime.jvm/runtime.jvm.iml" group="core" />
|
||||
|
||||
2
.idea/runConfigurations/Android_Studio.xml
generated
2
.idea/runConfigurations/Android_Studio.xml
generated
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Android Studio" type="Application" factoryName="Application">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<option name="MAIN_CLASS_NAME" value="com.intellij.idea.Main" />
|
||||
<option name="VM_PARAMETERS" value="-Didea.paths.selector=AndroidStudioPreview -Didea.platform.prefix=AndroidStudio -Xmx800m -XX:ReservedCodeCacheSize=64m -XX:MaxPermSize=450m -XX:+HeapDumpOnOutOfMemoryError -ea -Didea.is.internal=true -Didea.debug.mode=true -Didea.system.path=../system -Didea.config.path=../config -Dapple.laf.useScreenMenuBar=true -Dapple.awt.graphics.UseQuartz=true -Dsun.io.useCanonCaches=false -Dplugin.path=$PROJECT_DIR$/out/artifacts/Kotlin" />
|
||||
<option name="VM_PARAMETERS" value="-Didea.paths.selector=AndroidStudioPreview -Didea.platform.prefix=AndroidStudio -Xmx800m -XX:ReservedCodeCacheSize=64m -XX:MaxPermSize=450m -XX:+HeapDumpOnOutOfMemoryError -ea -Didea.is.internal=true -Didea.debug.mode=true -Didea.system.path=../system-idea -Didea.config.path=../config-idea -Dapple.laf.useScreenMenuBar=true -Dapple.awt.graphics.UseQuartz=true -Dsun.io.useCanonCaches=false -Dplugin.path=$PROJECT_DIR$/out/artifacts/Kotlin" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/android-studio/sdk/bin" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
|
||||
2
.idea/runConfigurations/IDEA.xml
generated
2
.idea/runConfigurations/IDEA.xml
generated
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="IDEA" type="Application" factoryName="Application">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<option name="MAIN_CLASS_NAME" value="com.intellij.idea.Main" />
|
||||
<option name="VM_PARAMETERS" value="-Xmx800m -XX:ReservedCodeCacheSize=64m -XX:MaxPermSize=450m -XX:+HeapDumpOnOutOfMemoryError -ea -Didea.is.internal=true -Didea.debug.mode=true -Didea.system.path=../system-idea -Didea.config.path=../config -Dapple.laf.useScreenMenuBar=true -Dapple.awt.graphics.UseQuartz=true -Dsun.io.useCanonCaches=false -Dplugin.path=$PROJECT_DIR$/out/artifacts/Kotlin -Dkotlin.internal.mode.enabled=true" />
|
||||
<option name="VM_PARAMETERS" value="-Xmx800m -XX:ReservedCodeCacheSize=64m -XX:MaxPermSize=450m -XX:+HeapDumpOnOutOfMemoryError -ea -Didea.is.internal=true -Didea.debug.mode=true -Didea.system.path=../system-idea -Didea.config.path=../config-idea -Dapple.laf.useScreenMenuBar=true -Dapple.awt.graphics.UseQuartz=true -Dsun.io.useCanonCaches=false -Dplugin.path=$PROJECT_DIR$/out/artifacts/Kotlin:$PROJECT_DIR$/out/artifacts/KotlinAndroidExtensionsPlugin -Dkotlin.internal.mode.enabled=true" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/ideaSDK/bin" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="IDEA (No ProcessCanceledException)" type="Application" factoryName="Application">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<option name="MAIN_CLASS_NAME" value="com.intellij.idea.Main" />
|
||||
<option name="VM_PARAMETERS" value="-Xmx800m -XX:ReservedCodeCacheSize=64m -XX:MaxPermSize=250m -XX:+HeapDumpOnOutOfMemoryError -ea -Didea.is.internal=true -Didea.debug.mode=true -Didea.system.path=../system-idea -Didea.config.path=../config -Dapple.laf.useScreenMenuBar=true -Dapple.awt.graphics.UseQuartz=true -Dsun.io.useCanonCaches=false -Dplugin.path=$PROJECT_DIR$/out/artifacts/Kotlin -Didea.ProcessCanceledException=disabled -Dkotlin.internal.mode.enabled=true" />
|
||||
<option name="VM_PARAMETERS" value="-Xmx800m -XX:ReservedCodeCacheSize=64m -XX:MaxPermSize=250m -XX:+HeapDumpOnOutOfMemoryError -ea -Didea.is.internal=true -Didea.debug.mode=true -Didea.system.path=../system-idea -Didea.config.path=../config-idea -Dapple.laf.useScreenMenuBar=true -Dapple.awt.graphics.UseQuartz=true -Dsun.io.useCanonCaches=false -Dplugin.path=$PROJECT_DIR$/out/artifacts/Kotlin:$PROJECT_DIR$/out/artifacts/KotlinAndroidExtensionsPlugin -Didea.ProcessCanceledException=disabled -Dkotlin.internal.mode.enabled=true" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/ideaSDK/bin" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
|
||||
35
.idea/runConfigurations/Incremental_Compilation_Tests.xml
generated
Normal file
35
.idea/runConfigurations/Incremental_Compilation_Tests.xml
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Incremental Compilation Tests" type="JUnit" factoryName="JUnit">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<module name="jps-plugin" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="" />
|
||||
<option name="PACKAGE_NAME" value="org.jetbrains.jet.jps.build" />
|
||||
<option name="MAIN_CLASS_NAME" value="org.jetbrains.jet.jps.build.IncrementalJpsTestGenerated" />
|
||||
<option name="METHOD_NAME" value="" />
|
||||
<option name="TEST_OBJECT" value="class" />
|
||||
<option name="VM_PARAMETERS" value="-ea -Xmx512m -XX:MaxPermSize=320m -Dkotlin.incremental.compilation=true" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
<value defaultName="moduleWithDependencies" />
|
||||
</option>
|
||||
<envs>
|
||||
<env name="kotlin.tests.actually.compile" value="false" />
|
||||
</envs>
|
||||
<patterns />
|
||||
<RunnerSettings RunnerId="Debug">
|
||||
<option name="DEBUG_PORT" value="" />
|
||||
<option name="TRANSPORT" value="0" />
|
||||
<option name="LOCAL" value="true" />
|
||||
</RunnerSettings>
|
||||
<RunnerSettings RunnerId="Run" />
|
||||
<ConfigurationWrapper RunnerId="Debug" />
|
||||
<ConfigurationWrapper RunnerId="Run" />
|
||||
<method>
|
||||
<option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/build.xml" target="dist_quick_compiler_only" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -27,6 +27,7 @@
|
||||
<patterns>
|
||||
<pattern testClass="org.jetbrains.jet.completion.JvmSmartCompletionTestGenerated" />
|
||||
<pattern testClass="org.jetbrains.jet.completion.handlers.SmartCompletionHandlerTestGenerated" />
|
||||
<pattern testClass="org.jetbrains.jet.completion.handlers.SmartCompletionMultifileHandlerTest" />
|
||||
</patterns>
|
||||
<RunnerSettings RunnerId="Debug">
|
||||
<option name="DEBUG_PORT" value="" />
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
<excludeFolder url="file://$MODULE_DIR$/android.tests.dependencies" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/dependencies" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/ideaSDK/androidSDK" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/ideaSDK/config" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/ideaSDK/config-idea" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/ideaSDK/system" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/ideaSDK/system-idea" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/libraries/.idea" />
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
name='com.intellij.codeInsight.NullableNotNullManager com.intellij.codeInsight.NullableNotNullManager getInstance(com.intellij.openapi.project.Project)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item
|
||||
name='com.intellij.codeInsight.PsiEquivalenceUtil com.intellij.psi.PsiElement[] getFilteredChildren(com.intellij.psi.PsiElement, com.intellij.openapi.util.Condition<com.intellij.psi.PsiElement>, boolean)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item name='com.intellij.codeInsight.NullableNotNullManager java.util.List<java.lang.String> getNotNulls()'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
|
||||
10
annotations/com/intellij/codeInsight/folding/annotations.xml
Normal file
10
annotations/com/intellij/codeInsight/folding/annotations.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<root>
|
||||
<item
|
||||
name='com.intellij.codeInsight.folding.CodeFoldingManager com.intellij.codeInsight.folding.CodeFoldingManager getInstance(com.intellij.openapi.project.Project)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item
|
||||
name='com.intellij.codeInsight.folding.CodeFoldingManager com.intellij.openapi.editor.FoldRegion[] getFoldRegionsAtOffset(com.intellij.openapi.editor.Editor, int)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
</root>
|
||||
@@ -0,0 +1,10 @@
|
||||
<root>
|
||||
<item
|
||||
name='com.intellij.codeInsight.folding.impl.CodeFoldingManagerImpl com.intellij.openapi.editor.FoldRegion[] getFoldRegionsAtOffset(com.intellij.openapi.editor.Editor, int)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item
|
||||
name='com.intellij.codeInsight.folding.impl.FoldingUtil com.intellij.openapi.editor.FoldRegion[] getFoldRegionsAtOffset(com.intellij.openapi.editor.Editor, int)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
</root>
|
||||
@@ -0,0 +1,6 @@
|
||||
<root>
|
||||
<item
|
||||
name='com.intellij.codeInsight.highlighting.HighlightManager com.intellij.codeInsight.highlighting.HighlightManager getInstance(com.intellij.openapi.project.Project)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
</root>
|
||||
@@ -0,0 +1,6 @@
|
||||
<root>
|
||||
<item
|
||||
name='com.intellij.debugger.ui.impl.watch.NodeManagerImpl java.util.Comparator<com.intellij.debugger.ui.tree.DebuggerTreeNode> getNodeComparator()'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
</root>
|
||||
10
annotations/com/intellij/debugger/ui/tree/annotations.xml
Normal file
10
annotations/com/intellij/debugger/ui/tree/annotations.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<root>
|
||||
<item
|
||||
name='com.intellij.debugger.ui.tree.NodeManager com.intellij.debugger.ui.tree.DebuggerTreeNode createMessageNode(java.lang.String)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item
|
||||
name='com.intellij.debugger.ui.tree.NodeManager com.intellij.debugger.ui.tree.DebuggerTreeNode createNode(com.intellij.debugger.ui.tree.NodeDescriptor, com.intellij.debugger.engine.evaluation.EvaluationContext)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
</root>
|
||||
@@ -0,0 +1,10 @@
|
||||
<root>
|
||||
<item
|
||||
name='com.intellij.debugger.ui.tree.render.ChildrenRenderer void buildChildren(com.sun.jdi.Value, com.intellij.debugger.ui.tree.render.ChildrenBuilder, com.intellij.debugger.engine.evaluation.EvaluationContext) 1'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item
|
||||
name='com.intellij.debugger.ui.tree.render.ChildrenRenderer void buildChildren(com.sun.jdi.Value, com.intellij.debugger.ui.tree.render.ChildrenBuilder, com.intellij.debugger.engine.evaluation.EvaluationContext) 2'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
</root>
|
||||
@@ -1,4 +1,7 @@
|
||||
<root>
|
||||
<item name='com.intellij.lang.ASTNode com.intellij.lang.ASTNode[] getChildren(com.intellij.psi.tree.TokenSet)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item name='com.intellij.lang.ASTNode java.lang.String getText()'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
|
||||
@@ -26,4 +26,8 @@
|
||||
name='com.intellij.openapi.roots.ProjectFileIndex.SERVICE com.intellij.openapi.roots.ProjectFileIndex getInstance(com.intellij.openapi.project.Project)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item
|
||||
name='com.intellij.openapi.roots.ProjectRootModificationTracker com.intellij.openapi.roots.ProjectRootModificationTracker getInstance(com.intellij.openapi.project.Project)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
</root>
|
||||
8
annotations/com/intellij/psi/codeStyle/annotations.xml
Normal file
8
annotations/com/intellij/psi/codeStyle/annotations.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<root>
|
||||
<item name='com.intellij.psi.codeStyle.NameUtil java.lang.String[] nameToWords(java.lang.String)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item name='com.intellij.psi.codeStyle.NameUtil java.util.List<java.lang.String> nameToWordsLowerCase(java.lang.String)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
</root>
|
||||
@@ -0,0 +1,8 @@
|
||||
<root>
|
||||
<item name='com.intellij.psi.impl.source.tree.CompositeElement com.intellij.lang.ASTNode[] getChildren(com.intellij.psi.tree.TokenSet)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item name='com.intellij.psi.impl.source.tree.LeafElement com.intellij.lang.ASTNode[] getChildren(com.intellij.psi.tree.TokenSet)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
</root>
|
||||
@@ -10,7 +10,10 @@
|
||||
name='com.intellij.psi.stubs.AbstractStubIndex java.util.Collection<Psi> get(Key, com.intellij.openapi.project.Project, com.intellij.psi.search.GlobalSearchScope) 2'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item
|
||||
<item name='com.intellij.psi.stubs.StubIndex com.intellij.psi.stubs.StubIndex getInstance()'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item
|
||||
name='com.intellij.psi.stubs.StubIndex java.util.Collection<Psi> get(com.intellij.psi.stubs.StubIndexKey<Key,Psi>, Key, com.intellij.openapi.project.Project, com.intellij.psi.search.GlobalSearchScope)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
name='com.intellij.psi.util.CachedValueProvider.Result com.intellij.psi.util.CachedValueProvider.Result<T> create(T, java.lang.Object...)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item
|
||||
<item
|
||||
name='com.intellij.psi.util.CachedValueProvider.Result com.intellij.psi.util.CachedValueProvider.Result<T> create(T, java.util.Collection<?>)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item
|
||||
name='com.intellij.psi.util.CachedValuesManager com.intellij.psi.util.CachedValue<T> createCachedValue(com.intellij.psi.util.CachedValueProvider<T>, boolean)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
<item name='com.intellij.refactoring.BaseRefactoringProcessor myProject'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item
|
||||
<item name='com.intellij.refactoring.BaseRefactoringProcessor void performRefactoring(com.intellij.usageView.UsageInfo[]) 0'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item
|
||||
name='com.intellij.refactoring.BaseRefactoringProcessor.ConflictsInTestsException java.util.Collection<java.lang.String> getMessages()'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<root>
|
||||
<item
|
||||
name='com.intellij.refactoring.move.moveClassesOrPackages.CommonMoveUtil com.intellij.refactoring.util.NonCodeUsageInfo[] retargetUsages(com.intellij.usageView.UsageInfo[], java.util.Map<com.intellij.psi.PsiElement,com.intellij.psi.PsiElement>)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
</root>
|
||||
@@ -14,10 +14,16 @@
|
||||
<item name='com.sun.jdi.Method java.util.List<com.sun.jdi.Type> argumentTypes()'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item name='com.sun.jdi.ReferenceType com.sun.jdi.ClassObjectReference classObject()'>
|
||||
<item name='com.sun.jdi.ObjectReference com.sun.jdi.ReferenceType referenceType()'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item name='com.sun.jdi.ReferenceType com.sun.jdi.ClassObjectReference classObject()'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item name='com.sun.jdi.ReferenceType java.util.List<com.sun.jdi.Location> allLineLocations()'>
|
||||
<item name='com.sun.jdi.ReferenceType java.util.List<com.sun.jdi.Field> allFields()'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item name='com.sun.jdi.ReferenceType java.util.List<com.sun.jdi.Location> allLineLocations()'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item name='com.sun.jdi.ReferenceType java.util.List<com.sun.jdi.Method> methodsByName(java.lang.String, java.lang.String)'>
|
||||
@@ -41,7 +47,10 @@
|
||||
<item name='com.sun.jdi.TypeComponent com.sun.jdi.ReferenceType declaringType()'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item name='com.sun.jdi.Value com.sun.jdi.Type type()'>
|
||||
<item name='com.sun.jdi.TypeComponent java.lang.String name()'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item name='com.sun.jdi.Value com.sun.jdi.Type type()'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item name='com.sun.jdi.VirtualMachine com.sun.jdi.BooleanValue mirrorOf(boolean)'>
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
<include name="core/serialization/src"/>
|
||||
<include name="core/descriptor.loader.java/src"/>
|
||||
<include name="compiler/frontend.java/src"/>
|
||||
<include name="compiler/frontend.android/src"/>
|
||||
<include name="core/serialization.java/src"/>
|
||||
<include name="compiler/backend-common/src"/>
|
||||
<include name="compiler/backend/src"/>
|
||||
@@ -86,6 +87,7 @@
|
||||
<include name="serialization/**"/>
|
||||
<include name="descriptor.loader.java/**"/>
|
||||
<include name="frontend.java/**"/>
|
||||
<include name="frontend.android/**"/>
|
||||
<include name="serialization.java/**"/>
|
||||
<include name="backend/**"/>
|
||||
<include name="backend-common/**"/>
|
||||
@@ -251,6 +253,7 @@
|
||||
<file name="kotlin_lib_ecma5.js"/>
|
||||
<file name="kotlin_lib.js"/>
|
||||
<file name="maps.js"/>
|
||||
<file name="long.js"/>
|
||||
</sources>
|
||||
|
||||
</closure-compiler>
|
||||
@@ -472,8 +475,12 @@
|
||||
public protected *;
|
||||
}
|
||||
|
||||
# for kdoc
|
||||
# for kdoc & dokka
|
||||
-keep class com.intellij.openapi.util.TextRange { *; }
|
||||
-keep class com.intellij.lang.impl.PsiBuilderImpl* {
|
||||
public protected *;
|
||||
}
|
||||
-keep class com.intellij.openapi.util.text.StringHash { *; }
|
||||
|
||||
-keepclassmembers enum * {
|
||||
public static **[] values();
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.jet.compiler.android;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.testFramework.UsefulTestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -31,6 +32,7 @@ import org.jetbrains.jet.codegen.GenerationUtils;
|
||||
import org.jetbrains.jet.compiler.PathManager;
|
||||
import org.jetbrains.jet.generators.tests.generator.TestGeneratorUtil;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.plugin.JetFileType;
|
||||
import org.jetbrains.jet.utils.Printer;
|
||||
import org.junit.Assert;
|
||||
|
||||
@@ -197,6 +199,9 @@ public class CodegenTestsOnAndroidGenerator extends UsefulTestCase {
|
||||
processFiles(printer, listFiles, holderFull, holderMock);
|
||||
}
|
||||
}
|
||||
else if (!FileUtilRt.getExtension(file.getName()).equals(JetFileType.INSTANCE.getDefaultExtension())) {
|
||||
// skip non kotlin files
|
||||
}
|
||||
else {
|
||||
String text = FileUtil.loadFile(file, true);
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ public class SpecialFiles {
|
||||
filesCompiledWithoutStdLib.add("kt4265.kt"); // OVERLOAD_RESOLUTION_AMBIGUITY
|
||||
filesCompiledWithoutStdLib.add("realStringRepeat.kt"); // OVERLOAD_RESOLUTION_AMBIGUITY
|
||||
filesCompiledWithoutStdLib.add("kt2395.kt"); // With MOCK_JDK
|
||||
filesCompiledWithoutStdLib.add("useAnonymousObjectAsIterator.kt"); // OVERLOAD_RESOLUTION_AMBIGUITY
|
||||
}
|
||||
|
||||
private static void fillExcludedFiles() {
|
||||
|
||||
@@ -40,10 +40,7 @@ import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
|
||||
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.*;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||
|
||||
@@ -243,7 +240,6 @@ public class AsmUtil {
|
||||
return NO_FLAG_PACKAGE_PRIVATE;
|
||||
}
|
||||
|
||||
|
||||
public static int getVisibilityAccessFlagForAnonymous(@NotNull ClassDescriptor descriptor) {
|
||||
if (isDeclarationInsideInlineFunction(descriptor)) {
|
||||
return ACC_PUBLIC;
|
||||
@@ -251,7 +247,7 @@ public class AsmUtil {
|
||||
return NO_FLAG_PACKAGE_PRIVATE;
|
||||
}
|
||||
|
||||
public static boolean isDeclarationInsideInlineFunction(@NotNull ClassDescriptor descriptor) {
|
||||
private static boolean isDeclarationInsideInlineFunction(@NotNull ClassDescriptor descriptor) {
|
||||
//NB: constructor context couldn't be inline
|
||||
DeclarationDescriptor parentDeclaration = descriptor.getContainingDeclaration();
|
||||
if (parentDeclaration instanceof SimpleFunctionDescriptor &&
|
||||
@@ -261,6 +257,31 @@ public class AsmUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int calculateInnerClassAccessFlags(@NotNull ClassDescriptor innerClass) {
|
||||
return getVisibilityAccessFlag(innerClass) |
|
||||
innerAccessFlagsForModalityAndKind(innerClass) |
|
||||
(innerClass.isInner() ? 0 : ACC_STATIC);
|
||||
}
|
||||
|
||||
private static int innerAccessFlagsForModalityAndKind(@NotNull ClassDescriptor innerClass) {
|
||||
switch (innerClass.getKind()) {
|
||||
case TRAIT:
|
||||
return ACC_ABSTRACT | ACC_INTERFACE;
|
||||
case ENUM_CLASS:
|
||||
return ACC_FINAL | ACC_ENUM;
|
||||
case ANNOTATION_CLASS:
|
||||
return ACC_ABSTRACT | ACC_ANNOTATION | ACC_INTERFACE;
|
||||
default:
|
||||
if (innerClass.getModality() == Modality.FINAL) {
|
||||
return ACC_FINAL;
|
||||
}
|
||||
else if (innerClass.getModality() == Modality.ABSTRACT) {
|
||||
return ACC_ABSTRACT;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int getDeprecatedAccessFlag(@NotNull MemberDescriptor descriptor) {
|
||||
if (descriptor instanceof PropertyAccessorDescriptor) {
|
||||
return KotlinBuiltIns.getInstance().isDeprecated(descriptor)
|
||||
@@ -705,12 +726,12 @@ public class AsmUtil {
|
||||
return expectedType;
|
||||
}
|
||||
|
||||
public static void pop(@NotNull InstructionAdapter v, @NotNull Type type) {
|
||||
public static void pop(@NotNull MethodVisitor v, @NotNull Type type) {
|
||||
if (type.getSize() == 2) {
|
||||
v.pop2();
|
||||
v.visitInsn(Opcodes.POP2);
|
||||
}
|
||||
else {
|
||||
v.pop();
|
||||
v.visitInsn(Opcodes.POP);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -806,11 +827,6 @@ public class AsmUtil {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Type getArrayOf(@NotNull String internalClassName) {
|
||||
return Type.getType("[L" + internalClassName + ";");
|
||||
}
|
||||
|
||||
public static int getReceiverIndex(@NotNull CodegenContext context, @NotNull CallableMemberDescriptor descriptor) {
|
||||
OwnerKind kind = context.getContextKind();
|
||||
//Trait always should have this descriptor
|
||||
|
||||
@@ -45,4 +45,9 @@ public class CodegenStatementVisitor extends JetVisitor<StackValue, StackValue>
|
||||
public StackValue visitWhenExpression(@NotNull JetWhenExpression expression, StackValue data) {
|
||||
return codegen.generateWhenExpression(expression, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackValue visitBlockExpression(@NotNull JetBlockExpression expression, StackValue data) {
|
||||
return codegen.generateBlock(expression, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.jetbrains.jet.codegen.binding.CalculatedClosure;
|
||||
import org.jetbrains.jet.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.jet.codegen.binding.MutableClosure;
|
||||
import org.jetbrains.jet.codegen.context.*;
|
||||
import org.jetbrains.jet.codegen.extensions.ExpressionCodegenExtension;
|
||||
import org.jetbrains.jet.codegen.inline.InlineCodegen;
|
||||
import org.jetbrains.jet.codegen.inline.InlineCodegenUtil;
|
||||
import org.jetbrains.jet.codegen.inline.NameGenerator;
|
||||
@@ -261,7 +262,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
}
|
||||
|
||||
public void gen(JetElement expr, Type type) {
|
||||
StackValue value = gen(expr);
|
||||
StackValue value = Type.VOID_TYPE.equals(type) ? genStatement(expr) : gen(expr);
|
||||
value.put(type, v);
|
||||
}
|
||||
|
||||
@@ -408,10 +409,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
StackValue conditionValue = gen(expression.getCondition());
|
||||
conditionValue.condJump(end, true, v);
|
||||
|
||||
JetExpression body = expression.getBody();
|
||||
if (body != null) {
|
||||
gen(body, Type.VOID_TYPE);
|
||||
}
|
||||
generateLoopBody(expression.getBody());
|
||||
|
||||
v.goTo(condition);
|
||||
|
||||
@@ -446,7 +444,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
statements.addAll(doWhileStatements);
|
||||
statements.add(condition);
|
||||
|
||||
conditionValue = generateBlock(statements, true, continueLabel);
|
||||
conditionValue = generateBlock(statements, false, continueLabel);
|
||||
}
|
||||
else {
|
||||
if (body != null) {
|
||||
@@ -633,10 +631,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
protected abstract void increment(@NotNull Label loopExit);
|
||||
|
||||
public void body() {
|
||||
JetExpression body = forExpression.getBody();
|
||||
if (body != null) {
|
||||
gen(body, Type.VOID_TYPE);
|
||||
}
|
||||
generateLoopBody(forExpression.getBody());
|
||||
}
|
||||
|
||||
private void scheduleLeaveVariable(Runnable runnable) {
|
||||
@@ -676,6 +671,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
}
|
||||
}
|
||||
|
||||
private void generateLoopBody(@Nullable JetExpression body) {
|
||||
if (body != null) {
|
||||
gen(body, Type.VOID_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
private class IteratorForLoopGenerator extends AbstractForLoopGenerator {
|
||||
|
||||
private int iteratorVarIndex;
|
||||
@@ -1277,10 +1278,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
|
||||
@Override
|
||||
public StackValue visitBlockExpression(@NotNull JetBlockExpression expression, StackValue receiver) {
|
||||
List<JetElement> statements = expression.getStatements();
|
||||
JetType unitType = KotlinBuiltIns.getInstance().getUnitType();
|
||||
boolean lastStatementIsExpression = !unitType.equals(bindingContext.get(EXPRESSION_TYPE, expression));
|
||||
return generateBlock(statements, lastStatementIsExpression);
|
||||
return generateBlock(expression, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1413,11 +1411,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
}
|
||||
}
|
||||
|
||||
private StackValue generateBlock(List<JetElement> statements, boolean lastStatementIsExpression) {
|
||||
return generateBlock(statements, lastStatementIsExpression, null);
|
||||
/* package */ StackValue generateBlock(@NotNull JetBlockExpression expression, boolean isStatement) {
|
||||
return generateBlock(expression.getStatements(), isStatement, null);
|
||||
}
|
||||
|
||||
private StackValue generateBlock(List<JetElement> statements, boolean lastStatementIsExpression, Label labelBeforeLastExpression) {
|
||||
private StackValue generateBlock(List<JetElement> statements, boolean isStatement, Label labelBeforeLastExpression) {
|
||||
Label blockEnd = new Label();
|
||||
|
||||
List<Function<StackValue, Void>> leaveTasks = Lists.newArrayList();
|
||||
@@ -1449,7 +1447,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
generateLocalFunctionDeclaration((JetNamedFunction) statement, leaveTasks);
|
||||
}
|
||||
|
||||
boolean isExpression = !iterator.hasNext() && lastStatementIsExpression;
|
||||
boolean isExpression = !iterator.hasNext() && !isStatement;
|
||||
if (isExpression && labelBeforeLastExpression != null) {
|
||||
v.mark(labelBeforeLastExpression);
|
||||
}
|
||||
@@ -1671,10 +1669,18 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
}
|
||||
|
||||
public void returnExpression(JetExpression expr) {
|
||||
StackValue lastValue = gen(expr);
|
||||
boolean isBlockedNamedFunction = expr instanceof JetBlockExpression && expr.getParent() instanceof JetNamedFunction;
|
||||
|
||||
// If generating body for named block-bodied function, generate it as sequence of statements
|
||||
gen(expr, isBlockedNamedFunction ? Type.VOID_TYPE : returnType);
|
||||
|
||||
// If it does not end with return we should return something
|
||||
// because if we don't there can be VerifyError (specific cases with Nothing-typed expressions)
|
||||
if (!endsWithReturn(expr)) {
|
||||
lastValue.put(returnType, v);
|
||||
if (isBlockedNamedFunction && !Type.VOID_TYPE.equals(expressionType(expr))) {
|
||||
StackValue.none().put(returnType, v);
|
||||
}
|
||||
|
||||
v.areturn(returnType);
|
||||
}
|
||||
}
|
||||
@@ -1725,6 +1731,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
if (descriptor instanceof PropertyDescriptor) {
|
||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
|
||||
|
||||
for (ExpressionCodegenExtension extension : ExpressionCodegenExtension.OBJECT$.getInstances(state.getProject())) {
|
||||
StackValue result = extension.apply(receiver, resolvedCall, new ExpressionCodegenExtension.Context(typeMapper, v));
|
||||
|
||||
if (result != null) return result;
|
||||
}
|
||||
|
||||
boolean directToField =
|
||||
expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER && contextKind() != OwnerKind.TRAIT_IMPL;
|
||||
JetExpression r = getReceiverForSelector(expression);
|
||||
@@ -1754,8 +1766,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
return StackValue.field(type, type, descriptor.getName().asString(), true);
|
||||
}
|
||||
ClassDescriptor classObjectDescriptor = classDescriptor.getClassObjectDescriptor();
|
||||
assert classObjectDescriptor != null : "Class object is not found for " + descriptor;
|
||||
return StackValue.singleton(classObjectDescriptor, typeMapper);
|
||||
if (classObjectDescriptor != null) {
|
||||
return StackValue.singleton(classObjectDescriptor, typeMapper);
|
||||
}
|
||||
return StackValue.none();
|
||||
}
|
||||
|
||||
if (descriptor instanceof TypeParameterDescriptor) {
|
||||
|
||||
@@ -148,7 +148,9 @@ public class FunctionCodegen extends ParentCodegenAware {
|
||||
|
||||
generateParameterAnnotations(functionDescriptor, mv, jvmSignature);
|
||||
|
||||
generateJetValueParameterAnnotations(mv, functionDescriptor, jvmSignature);
|
||||
if (state.getClassBuilderMode() != ClassBuilderMode.LIGHT_CLASSES) {
|
||||
generateJetValueParameterAnnotations(mv, functionDescriptor, jvmSignature);
|
||||
}
|
||||
|
||||
generateBridges(functionDescriptor);
|
||||
|
||||
|
||||
@@ -285,48 +285,16 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
|
||||
private void writeInnerClass(@NotNull ClassDescriptor innerClass) {
|
||||
// TODO: proper access
|
||||
int innerClassAccess = getVisibilityAccessFlag(innerClass);
|
||||
if (innerClass.getModality() == Modality.FINAL) {
|
||||
innerClassAccess |= ACC_FINAL;
|
||||
}
|
||||
else if (innerClass.getModality() == Modality.ABSTRACT) {
|
||||
innerClassAccess |= ACC_ABSTRACT;
|
||||
}
|
||||
|
||||
if (innerClass.getKind() == ClassKind.TRAIT) {
|
||||
innerClassAccess |= ACC_INTERFACE;
|
||||
}
|
||||
else if (innerClass.getKind() == ClassKind.ENUM_CLASS) {
|
||||
innerClassAccess |= ACC_ENUM;
|
||||
}
|
||||
|
||||
if (!innerClass.isInner()) {
|
||||
innerClassAccess |= ACC_STATIC;
|
||||
}
|
||||
|
||||
// TODO: cache internal names
|
||||
DeclarationDescriptor containing = innerClass.getContainingDeclaration();
|
||||
String outerClassInternalName = containing instanceof ClassDescriptor ? getInternalNameForImpl((ClassDescriptor) containing) : null;
|
||||
String outerClassInternalName =
|
||||
containing instanceof ClassDescriptor ? typeMapper.mapClass((ClassDescriptor) containing).getInternalName() : null;
|
||||
|
||||
String innerClassInternalName;
|
||||
String innerName;
|
||||
String innerName = isClassObject(innerClass)
|
||||
? JvmAbi.CLASS_OBJECT_CLASS_NAME
|
||||
: innerClass.getName().isSpecial() ? null : innerClass.getName().asString();
|
||||
|
||||
if (isClassObject(innerClass)) {
|
||||
innerName = JvmAbi.CLASS_OBJECT_CLASS_NAME;
|
||||
innerClassInternalName = outerClassInternalName + JvmAbi.CLASS_OBJECT_SUFFIX;
|
||||
}
|
||||
else {
|
||||
innerName = innerClass.getName().isSpecial() ? null : innerClass.getName().asString();
|
||||
innerClassInternalName = getInternalNameForImpl(innerClass);
|
||||
}
|
||||
|
||||
v.visitInnerClass(innerClassInternalName, outerClassInternalName, innerName, innerClassAccess);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getInternalNameForImpl(@NotNull ClassDescriptor descriptor) {
|
||||
return typeMapper.mapClass(descriptor).getInternalName();
|
||||
String innerClassInternalName = typeMapper.mapClass(innerClass).getInternalName();
|
||||
v.visitInnerClass(innerClassInternalName, outerClassInternalName, innerName, calculateInnerClassAccessFlags(innerClass));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.jetbrains.jet.codegen;
|
||||
import com.intellij.openapi.vfs.StandardFileSystems;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.containers.Stack;
|
||||
import kotlin.Function1;
|
||||
import kotlin.KotlinPackage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -67,10 +66,6 @@ public class JvmCodegenUtil {
|
||||
return closure.getCaptureThis() == null && closure.getCaptureReceiverType() == null && closure.getCaptureVariables().isEmpty();
|
||||
}
|
||||
|
||||
public static <T> T peekFromStack(Stack<T> stack) {
|
||||
return stack.empty() ? null : stack.peek();
|
||||
}
|
||||
|
||||
private static boolean isCallInsideSameClassAsDeclared(@NotNull CallableMemberDescriptor descriptor, @NotNull CodegenContext context) {
|
||||
boolean isFakeOverride = descriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE;
|
||||
boolean isDelegate = descriptor.getKind() == CallableMemberDescriptor.Kind.DELEGATION;
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
@@ -247,8 +248,16 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
|
||||
type = boxType(type);
|
||||
}
|
||||
codegen.gen(initializer, type);
|
||||
|
||||
propValue.store(type, codegen.v);
|
||||
|
||||
ResolvedCall<FunctionDescriptor> pdResolvedCall =
|
||||
bindingContext.get(BindingContext.DELEGATED_PROPERTY_PD_RESOLVED_CALL, propertyDescriptor);
|
||||
if (pdResolvedCall != null) {
|
||||
int index = PropertyCodegen.indexOfDelegatedProperty(property);
|
||||
StackValue lastValue = PropertyCodegen.invokeDelegatedPropertyConventionMethod(propertyDescriptor, codegen,
|
||||
state.getTypeMapper(), pdResolvedCall, index, 0);
|
||||
lastValue.put(Type.VOID_TYPE, codegen.v);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldInitializeProperty(@NotNull JetProperty property) {
|
||||
|
||||
@@ -344,7 +344,7 @@ public class PropertyCodegen {
|
||||
functionCodegen.generateMethod(OtherOrigin(accessor != null ? accessor : p, accessorDescriptor), signature, accessorDescriptor, strategy);
|
||||
}
|
||||
|
||||
private static int indexOfDelegatedProperty(@NotNull JetProperty property) {
|
||||
public static int indexOfDelegatedProperty(@NotNull JetProperty property) {
|
||||
PsiElement parent = property.getParent();
|
||||
JetDeclarationContainer container;
|
||||
if (parent instanceof JetClassBody) {
|
||||
@@ -409,6 +409,46 @@ public class PropertyCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
public static StackValue invokeDelegatedPropertyConventionMethod(
|
||||
@NotNull PropertyDescriptor propertyDescriptor,
|
||||
@NotNull ExpressionCodegen codegen,
|
||||
@NotNull JetTypeMapper typeMapper,
|
||||
@NotNull ResolvedCall<FunctionDescriptor> resolvedCall,
|
||||
final int indexInPropertyMetadataArray,
|
||||
int propertyMetadataArgumentIndex
|
||||
) {
|
||||
if (codegen.getContext().getContextKind() != OwnerKind.PACKAGE) {
|
||||
codegen.v.load(0, OBJECT_TYPE);
|
||||
}
|
||||
|
||||
CodegenContext<? extends ClassOrPackageFragmentDescriptor> ownerContext = codegen.getContext().getClassOrPackageParentContext();
|
||||
final Type owner;
|
||||
if (ownerContext instanceof ClassContext) {
|
||||
owner = typeMapper.mapClass(((ClassContext) ownerContext).getContextDescriptor());
|
||||
}
|
||||
else if (ownerContext instanceof PackageContext) {
|
||||
owner = ((PackageContext) ownerContext).getPackagePartType();
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Unknown context: " + ownerContext);
|
||||
}
|
||||
|
||||
codegen.tempVariables.put(
|
||||
resolvedCall.getCall().getValueArguments().get(propertyMetadataArgumentIndex).asElement(),
|
||||
new StackValue(PROPERTY_METADATA_TYPE) {
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
v.getstatic(owner.getInternalName(), JvmAbi.PROPERTY_METADATA_ARRAY_NAME, "[" + PROPERTY_METADATA_TYPE);
|
||||
v.iconst(indexInPropertyMetadataArray);
|
||||
StackValue.arrayElement(PROPERTY_METADATA_TYPE).put(type, v);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
StackValue delegatedProperty = codegen.intermediateValueForProperty(propertyDescriptor, true, null);
|
||||
return codegen.invokeFunction(resolvedCall, delegatedProperty);
|
||||
}
|
||||
|
||||
private static class DelegatedPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> {
|
||||
private final int index;
|
||||
|
||||
@@ -426,37 +466,8 @@ public class PropertyCodegen {
|
||||
bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, callableDescriptor);
|
||||
assert resolvedCall != null : "Resolve call should be recorded for delegate call " + signature.toString();
|
||||
|
||||
if (codegen.getContext().getContextKind() != OwnerKind.PACKAGE) {
|
||||
v.load(0, OBJECT_TYPE);
|
||||
}
|
||||
|
||||
CodegenContext<? extends ClassOrPackageFragmentDescriptor> ownerContext = codegen.getContext().getClassOrPackageParentContext();
|
||||
final Type owner;
|
||||
if (ownerContext instanceof ClassContext) {
|
||||
owner = state.getTypeMapper().mapClass(((ClassContext) ownerContext).getContextDescriptor());
|
||||
}
|
||||
else if (ownerContext instanceof PackageContext) {
|
||||
owner = ((PackageContext) ownerContext).getPackagePartType();
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Unknown context: " + ownerContext);
|
||||
}
|
||||
|
||||
codegen.tempVariables.put(
|
||||
resolvedCall.getCall().getValueArguments().get(1).asElement(),
|
||||
new StackValue(PROPERTY_METADATA_TYPE) {
|
||||
@Override
|
||||
public void put(Type type, InstructionAdapter v) {
|
||||
v.getstatic(owner.getInternalName(), JvmAbi.PROPERTY_METADATA_ARRAY_NAME, "[" + PROPERTY_METADATA_TYPE);
|
||||
v.iconst(index);
|
||||
StackValue.arrayElement(PROPERTY_METADATA_TYPE).put(type, v);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
StackValue delegatedProperty = codegen.intermediateValueForProperty(callableDescriptor.getCorrespondingProperty(), true, null);
|
||||
StackValue lastValue = codegen.invokeFunction(resolvedCall, delegatedProperty);
|
||||
|
||||
StackValue lastValue = invokeDelegatedPropertyConventionMethod(callableDescriptor.getCorrespondingProperty(),
|
||||
codegen, state.getTypeMapper(), resolvedCall, index, 1);
|
||||
Type asmType = signature.getReturnType();
|
||||
lastValue.put(asmType, v);
|
||||
v.areturn(asmType);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import kotlin.Function0;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.codegen.context.CodegenContext;
|
||||
@@ -38,7 +39,8 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.jet.codegen.AsmUtil.method;
|
||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
|
||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.CLASS_FOR_SCRIPT;
|
||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.asmTypeForScriptDescriptor;
|
||||
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*;
|
||||
import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin;
|
||||
import static org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
|
||||
@@ -52,17 +54,17 @@ public class ScriptCodegen extends MemberCodegen<JetScript> {
|
||||
@NotNull GenerationState state,
|
||||
@NotNull CodegenContext parentContext
|
||||
) {
|
||||
ScriptDescriptor scriptDescriptor = state.getBindingContext().get(BindingContext.SCRIPT, declaration);
|
||||
BindingContext bindingContext = state.getBindingContext();
|
||||
ScriptDescriptor scriptDescriptor = bindingContext.get(BindingContext.SCRIPT, declaration);
|
||||
assert scriptDescriptor != null;
|
||||
|
||||
ClassDescriptor classDescriptorForScript = state.getBindingContext().get(CLASS_FOR_SCRIPT, scriptDescriptor);
|
||||
ClassDescriptor classDescriptorForScript = bindingContext.get(CLASS_FOR_SCRIPT, scriptDescriptor);
|
||||
assert classDescriptorForScript != null;
|
||||
|
||||
Type className = state.getBindingContext().get(ASM_TYPE, classDescriptorForScript);
|
||||
assert className != null;
|
||||
Type classType = asmTypeForScriptDescriptor(bindingContext, scriptDescriptor);
|
||||
|
||||
ClassBuilder builder = state.getFactory().newVisitor(OtherOrigin(declaration, classDescriptorForScript),
|
||||
className, declaration.getContainingFile());
|
||||
classType, declaration.getContainingFile());
|
||||
List<ScriptDescriptor> earlierScripts = state.getEarlierScriptsForReplInterpreter();
|
||||
ScriptContext scriptContext = parentContext.intoScript(
|
||||
scriptDescriptor,
|
||||
@@ -90,8 +92,7 @@ public class ScriptCodegen extends MemberCodegen<JetScript> {
|
||||
|
||||
@Override
|
||||
protected void generateDeclaration() {
|
||||
Type classType = bindingContext.get(ASM_TYPE, context.getContextDescriptor());
|
||||
assert classType != null;
|
||||
Type classType = typeMapper.mapClass(context.getContextDescriptor());
|
||||
|
||||
v.defineClass(scriptDeclaration,
|
||||
V1_6,
|
||||
@@ -99,7 +100,7 @@ public class ScriptCodegen extends MemberCodegen<JetScript> {
|
||||
classType.getInternalName(),
|
||||
null,
|
||||
"java/lang/Object",
|
||||
new String[0]);
|
||||
ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
|
||||
generateReflectionObjectField(state, classType, v, method("kClassFromKotlin", K_CLASS_IMPL_TYPE, getType(Class.class)),
|
||||
JvmAbi.KOTLIN_CLASS_FIELD_NAME, createOrGetClInitCodegen().v);
|
||||
@@ -124,6 +125,7 @@ public class ScriptCodegen extends MemberCodegen<JetScript> {
|
||||
@NotNull ClassBuilder classBuilder,
|
||||
@NotNull final MethodContext methodContext
|
||||
) {
|
||||
//noinspection ConstantConditions
|
||||
Type blockType = typeMapper.mapType(scriptDescriptor.getScriptCodeDescriptor().getReturnType());
|
||||
|
||||
PropertyDescriptor scriptResultProperty = scriptDescriptor.getScriptResultProperty();
|
||||
@@ -142,8 +144,7 @@ public class ScriptCodegen extends MemberCodegen<JetScript> {
|
||||
|
||||
final InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
|
||||
Type classType = bindingContext.get(ASM_TYPE, classDescriptorForScript);
|
||||
assert classType != null;
|
||||
Type classType = typeMapper.mapType(classDescriptorForScript);
|
||||
|
||||
iv.load(0, classType);
|
||||
iv.invokespecial("java/lang/Object", "<init>", "()V", false);
|
||||
|
||||
@@ -933,7 +933,8 @@ public abstract class StackValue {
|
||||
}
|
||||
}
|
||||
|
||||
public static Type sharedTypeForType(Type type) {
|
||||
@NotNull
|
||||
public static Type sharedTypeForType(@NotNull Type type) {
|
||||
switch (type.getSort()) {
|
||||
case Type.OBJECT:
|
||||
case Type.ARRAY:
|
||||
|
||||
@@ -23,7 +23,10 @@ import com.intellij.util.containers.Stack;
|
||||
import kotlin.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.codegen.*;
|
||||
import org.jetbrains.jet.codegen.AsmUtil;
|
||||
import org.jetbrains.jet.codegen.JvmRuntimeTypes;
|
||||
import org.jetbrains.jet.codegen.SamCodegenUtil;
|
||||
import org.jetbrains.jet.codegen.SamType;
|
||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
import org.jetbrains.jet.codegen.when.SwitchCodegenUtil;
|
||||
import org.jetbrains.jet.codegen.when.WhenByEnumsMapping;
|
||||
@@ -33,6 +36,7 @@ import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ExpressionValueArgument;
|
||||
@@ -42,17 +46,15 @@ import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.constants.EnumValue;
|
||||
import org.jetbrains.jet.lang.resolve.constants.NullValue;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
|
||||
import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.source.SourcePackage;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.codegen.JvmCodegenUtil.peekFromStack;
|
||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
||||
import static org.jetbrains.jet.lang.resolve.name.SpecialNames.safeIdentifier;
|
||||
@@ -105,6 +107,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
|
||||
@NotNull
|
||||
private ClassDescriptor recordClassForFunction(
|
||||
@NotNull JetElement element,
|
||||
@NotNull FunctionDescriptor funDescriptor,
|
||||
@NotNull Collection<JetType> supertypes,
|
||||
@NotNull String name
|
||||
@@ -112,7 +115,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
String simpleName = name.substring(name.lastIndexOf('/') + 1);
|
||||
ClassDescriptorImpl classDescriptor = new ClassDescriptorImpl(
|
||||
funDescriptor.getContainingDeclaration(), Name.special("<closure-" + simpleName + ">"), Modality.FINAL, supertypes,
|
||||
SourceElement.NO_SOURCE
|
||||
SourcePackage.toSourceElement(element)
|
||||
);
|
||||
classDescriptor.initialize(JetScope.EMPTY, Collections.<ConstructorDescriptor>emptySet(), null);
|
||||
|
||||
@@ -191,7 +194,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
JetPsiUtil.getElementTextWithContext(classObject));
|
||||
|
||||
String name = peekFromStack(nameStack) + JvmAbi.CLASS_OBJECT_SUFFIX;
|
||||
recordClosure(classObject, classDescriptor, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
pushClassDescriptor(classDescriptor);
|
||||
nameStack.push(name);
|
||||
@@ -213,7 +216,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
if (classDescriptor == null) return;
|
||||
|
||||
String name = getName(classDescriptor);
|
||||
recordClosure(declaration, classDescriptor, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
pushClassDescriptor(classDescriptor);
|
||||
nameStack.push(name);
|
||||
@@ -232,7 +235,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
if (classDescriptor == null) return;
|
||||
|
||||
String name = getName(classDescriptor);
|
||||
recordClosure(klass, classDescriptor, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
pushClassDescriptor(classDescriptor);
|
||||
nameStack.push(name);
|
||||
@@ -258,11 +261,10 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
}
|
||||
|
||||
String name = inventAnonymousClassName(expression.getObjectDeclaration());
|
||||
recordClosure(expression.getObjectDeclaration(), classDescriptor, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
pushClassDescriptor(classDescriptor);
|
||||
//noinspection ConstantConditions
|
||||
nameStack.push(bindingContext.get(ASM_TYPE, classDescriptor).getInternalName());
|
||||
nameStack.push(CodegenBinding.getAsmType(bindingContext, classDescriptor).getInternalName());
|
||||
super.visitObjectLiteralExpression(expression);
|
||||
nameStack.pop();
|
||||
popClassDescriptor();
|
||||
@@ -278,8 +280,8 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
|
||||
String name = inventAnonymousClassName(expression);
|
||||
Collection<JetType> supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor);
|
||||
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, supertypes, name);
|
||||
recordClosure(functionLiteral, classDescriptor, name);
|
||||
ClassDescriptor classDescriptor = recordClassForFunction(functionLiteral, functionDescriptor, supertypes, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
pushClassDescriptor(classDescriptor);
|
||||
nameStack.push(name);
|
||||
@@ -329,8 +331,8 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
runtimeTypes.getSupertypesForFunctionReference((FunctionDescriptor) referencedFunction.getResultingDescriptor());
|
||||
|
||||
String name = inventAnonymousClassName(expression);
|
||||
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, supertypes, name);
|
||||
recordClosure(expression, classDescriptor, name);
|
||||
ClassDescriptor classDescriptor = recordClassForFunction(expression, functionDescriptor, supertypes, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
pushClassDescriptor(classDescriptor);
|
||||
nameStack.push(name);
|
||||
@@ -340,12 +342,8 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
}
|
||||
|
||||
|
||||
private void recordClosure(
|
||||
@NotNull JetElement element,
|
||||
@NotNull ClassDescriptor classDescriptor,
|
||||
@NotNull String name
|
||||
) {
|
||||
CodegenBinding.recordClosure(bindingTrace, element, classDescriptor, getOuterClassDescriptor(), Type.getObjectType(name));
|
||||
private void recordClosure(@NotNull ClassDescriptor classDescriptor, @NotNull String name) {
|
||||
CodegenBinding.recordClosure(bindingTrace, classDescriptor, getOuterClassDescriptor(), Type.getObjectType(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -380,8 +378,8 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
else {
|
||||
String name = inventAnonymousClassName(function);
|
||||
Collection<JetType> supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor);
|
||||
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, supertypes, name);
|
||||
recordClosure(function, classDescriptor, name);
|
||||
ClassDescriptor classDescriptor = recordClassForFunction(function, functionDescriptor, supertypes, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
pushClassDescriptor(classDescriptor);
|
||||
nameStack.push(name);
|
||||
@@ -401,14 +399,12 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
return peek + '$' + name;
|
||||
}
|
||||
else if (containingDeclaration instanceof PackageFragmentDescriptor) {
|
||||
FqName qualifiedName = ((PackageFragmentDescriptor) containingDeclaration).getFqName();
|
||||
String packageClassShortName = PackageClassUtils.getPackageClassName(qualifiedName);
|
||||
String packageClassName = peek.isEmpty() ? packageClassShortName : peek + "/" + packageClassShortName;
|
||||
return packageClassName + '$' + name;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
JetFile containingFile = DescriptorToSourceUtils.getContainingFile(descriptor);
|
||||
assert containingFile != null : "File not found for " + descriptor;
|
||||
return PackagePartClassUtils.getPackagePartInternalName(containingFile) + '$' + name;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -498,66 +494,56 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
@Override
|
||||
public void visitWhenExpression(@NotNull JetWhenExpression expression) {
|
||||
super.visitWhenExpression(expression);
|
||||
if (isWhenWithEnums(expression)) {
|
||||
String currentClassName = getCurrentTopLevelClassOrPackagePartInternalName(expression.getContainingJetFile());
|
||||
if (!isWhenWithEnums(expression)) return;
|
||||
|
||||
if (bindingContext.get(MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE, currentClassName) == null) {
|
||||
bindingTrace.record(
|
||||
MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE,
|
||||
currentClassName,
|
||||
new ArrayList<WhenByEnumsMapping>()
|
||||
);
|
||||
}
|
||||
String currentClassName = getCurrentTopLevelClassOrPackagePartInternalName(expression.getContainingJetFile());
|
||||
|
||||
List<WhenByEnumsMapping> mappings = bindingContext.get(MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE, currentClassName);
|
||||
assert mappings != null : "guaranteed by contract";
|
||||
|
||||
int fieldNumber = mappings.size();
|
||||
|
||||
JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression.getSubjectExpression());
|
||||
assert type != null : "should not be null in a valid when by enums";
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) type.getConstructor().getDeclarationDescriptor();
|
||||
assert classDescriptor != null : "because it's enum";
|
||||
|
||||
WhenByEnumsMapping mapping = new WhenByEnumsMapping(
|
||||
CodegenBinding.getAsmType(bindingContext, classDescriptor).getInternalName(),
|
||||
currentClassName,
|
||||
fieldNumber
|
||||
);
|
||||
|
||||
for (CompileTimeConstant constant : SwitchCodegenUtil.getAllConstants(expression, bindingContext)) {
|
||||
if (constant instanceof NullValue) continue;
|
||||
|
||||
assert constant instanceof EnumValue : "expression in when should be EnumValue";
|
||||
mapping.putFirstTime((EnumValue) constant, mapping.size() + 1);
|
||||
}
|
||||
|
||||
mappings.add(mapping);
|
||||
|
||||
bindingTrace.record(MAPPING_FOR_WHEN_BY_ENUM, expression, mapping);
|
||||
if (bindingContext.get(MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE, currentClassName) == null) {
|
||||
bindingTrace.record(MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE, currentClassName, new ArrayList<WhenByEnumsMapping>(1));
|
||||
}
|
||||
|
||||
List<WhenByEnumsMapping> mappings = bindingContext.get(MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE, currentClassName);
|
||||
assert mappings != null : "guaranteed by contract";
|
||||
|
||||
int fieldNumber = mappings.size();
|
||||
|
||||
JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression.getSubjectExpression());
|
||||
assert type != null : "should not be null in a valid when by enums";
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) type.getConstructor().getDeclarationDescriptor();
|
||||
assert classDescriptor != null : "because it's enum";
|
||||
|
||||
WhenByEnumsMapping mapping = new WhenByEnumsMapping(classDescriptor, currentClassName, fieldNumber);
|
||||
|
||||
for (CompileTimeConstant constant : SwitchCodegenUtil.getAllConstants(expression, bindingContext)) {
|
||||
if (constant instanceof NullValue) continue;
|
||||
|
||||
assert constant instanceof EnumValue : "expression in when should be EnumValue";
|
||||
mapping.putFirstTime((EnumValue) constant, mapping.size() + 1);
|
||||
}
|
||||
|
||||
mappings.add(mapping);
|
||||
|
||||
bindingTrace.record(MAPPING_FOR_WHEN_BY_ENUM, expression, mapping);
|
||||
}
|
||||
|
||||
private boolean isWhenWithEnums(@NotNull JetWhenExpression expression) {
|
||||
return WhenChecker.isWhenByEnum(expression, bindingContext) &&
|
||||
SwitchCodegenUtil.checkAllItemsAreConstantsSatisfying(
|
||||
expression,
|
||||
bindingContext,
|
||||
new Function1<CompileTimeConstant, Boolean>() {
|
||||
@Override
|
||||
public Boolean invoke(
|
||||
@NotNull CompileTimeConstant constant
|
||||
) {
|
||||
return constant instanceof EnumValue || constant instanceof NullValue;
|
||||
}
|
||||
}
|
||||
);
|
||||
SwitchCodegenUtil.checkAllItemsAreConstantsSatisfying(
|
||||
expression,
|
||||
bindingContext,
|
||||
new Function1<CompileTimeConstant, Boolean>() {
|
||||
@Override
|
||||
public Boolean invoke(@NotNull CompileTimeConstant constant) {
|
||||
return constant instanceof EnumValue || constant instanceof NullValue;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getCurrentTopLevelClassOrPackagePartInternalName(@NotNull JetFile file) {
|
||||
ListIterator<ClassDescriptorWithState> iterator = classStack.listIterator(classStack.size());
|
||||
while(iterator.hasPrevious()) {
|
||||
while (iterator.hasPrevious()) {
|
||||
ClassDescriptor previous = iterator.previous().getDescriptor();
|
||||
if (DescriptorUtils.isTopLevelOrInnerClass(previous)) {
|
||||
return CodegenBinding.getAsmType(bindingContext, previous).getInternalName();
|
||||
@@ -566,4 +552,8 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
|
||||
return PackagePartClassUtils.getPackagePartInternalName(file);
|
||||
}
|
||||
|
||||
private static <T> T peekFromStack(@NotNull Stack<T> stack) {
|
||||
return stack.empty() ? null : stack.peek();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,12 +28,9 @@ import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.resolve.name.SpecialNames;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
import org.jetbrains.jet.util.slicedmap.BasicWritableSlice;
|
||||
import org.jetbrains.jet.util.slicedmap.Slices;
|
||||
@@ -44,7 +41,9 @@ import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.codegen.JvmCodegenUtil.isInterface;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage.getResolvedCall;
|
||||
import static org.jetbrains.jet.lang.resolve.source.SourcePackage.toSourceElement;
|
||||
|
||||
public class CodegenBinding {
|
||||
public static final WritableSlice<ClassDescriptor, MutableClosure> CLOSURE = Slices.createSimpleSlice();
|
||||
@@ -53,7 +52,7 @@ public class CodegenBinding {
|
||||
|
||||
public static final WritableSlice<ScriptDescriptor, ClassDescriptor> CLASS_FOR_SCRIPT = Slices.createSimpleSlice();
|
||||
|
||||
public static final WritableSlice<ClassDescriptor, Type> ASM_TYPE = Slices.createCollectiveSlice();
|
||||
public static final WritableSlice<ClassDescriptor, Type> ASM_TYPE = Slices.createSimpleSlice();
|
||||
|
||||
public static final WritableSlice<ClassDescriptor, Boolean> ENUM_ENTRY_CLASS_NEED_SUBCLASS = Slices.createSimpleSetSlice();
|
||||
|
||||
@@ -138,22 +137,6 @@ public class CodegenBinding {
|
||||
return getAsmType(bindingContext, anonymousClassForFunction(bindingContext, descriptor));
|
||||
}
|
||||
|
||||
// SCRIPT: register asmType for script descriptor, move to ScriptingUtil
|
||||
public static void registerClassNameForScript(
|
||||
BindingTrace bindingTrace,
|
||||
@NotNull ScriptDescriptor scriptDescriptor,
|
||||
@NotNull Type asmType
|
||||
) {
|
||||
ClassDescriptorImpl classDescriptor =
|
||||
new ClassDescriptorImpl(scriptDescriptor, Name.special("<script-" + asmType.getInternalName() + ">"), Modality.FINAL,
|
||||
Collections.singleton(KotlinBuiltIns.getInstance().getAnyType()), SourceElement.NO_SOURCE);
|
||||
classDescriptor.initialize(JetScope.EMPTY, Collections.<ConstructorDescriptor>emptySet(), null);
|
||||
|
||||
recordClosure(bindingTrace, null, classDescriptor, null, asmType);
|
||||
|
||||
bindingTrace.record(CLASS_FOR_SCRIPT, scriptDescriptor, classDescriptor);
|
||||
}
|
||||
|
||||
public static boolean canHaveOuter(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor classDescriptor) {
|
||||
if (classDescriptor.getKind() != ClassKind.CLASS) {
|
||||
return false;
|
||||
@@ -168,40 +151,28 @@ public class CodegenBinding {
|
||||
}
|
||||
|
||||
static void recordClosure(
|
||||
@NotNull BindingTrace bindingTrace,
|
||||
@Nullable JetElement element,
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull ClassDescriptor classDescriptor,
|
||||
@Nullable ClassDescriptor enclosing,
|
||||
@NotNull Type asmType
|
||||
) {
|
||||
ResolvedCall<ConstructorDescriptor> superCall = findSuperCall(bindingTrace.getBindingContext(), element);
|
||||
JetElement element = (JetElement) descriptorToDeclaration(classDescriptor);
|
||||
assert element != null : "No source element for " + classDescriptor;
|
||||
|
||||
CallableDescriptor enclosingReceiver = null;
|
||||
if (classDescriptor.getContainingDeclaration() instanceof CallableDescriptor) {
|
||||
enclosingReceiver = (CallableDescriptor) classDescriptor.getContainingDeclaration();
|
||||
enclosingReceiver = enclosingReceiver instanceof PropertyAccessorDescriptor
|
||||
? ((PropertyAccessorDescriptor) enclosingReceiver).getCorrespondingProperty()
|
||||
: enclosingReceiver;
|
||||
|
||||
if (enclosingReceiver.getReceiverParameter() == null) {
|
||||
enclosingReceiver = null;
|
||||
}
|
||||
}
|
||||
|
||||
MutableClosure closure = new MutableClosure(superCall, enclosing, enclosingReceiver);
|
||||
|
||||
assert PsiCodegenPredictor.checkPredictedNameFromPsi(classDescriptor, asmType);
|
||||
bindingTrace.record(ASM_TYPE, classDescriptor, asmType);
|
||||
bindingTrace.record(CLOSURE, classDescriptor, closure);
|
||||
MutableClosure closure = new MutableClosure(classDescriptor, findSuperCall(trace.getBindingContext(), element), enclosing);
|
||||
|
||||
if (classDescriptor.isInner()) {
|
||||
closure.setCaptureThis();
|
||||
}
|
||||
|
||||
assert PsiCodegenPredictor.checkPredictedNameFromPsi(classDescriptor, asmType);
|
||||
trace.record(ASM_TYPE, classDescriptor, asmType);
|
||||
trace.record(CLOSURE, classDescriptor, closure);
|
||||
|
||||
//TEMPORARY EAT INNER CLASS INFO FOR FUNCTION LITERALS
|
||||
//TODO: we should understand that lambda/closure would be inlined and don't generate inner class record
|
||||
if (enclosing != null && !(element instanceof JetFunctionLiteral)) {
|
||||
recordInnerClass(bindingTrace, enclosing, classDescriptor);
|
||||
recordInnerClass(trace, enclosing, classDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,16 +190,21 @@ public class CodegenBinding {
|
||||
}
|
||||
|
||||
// SCRIPT: register asmType for script, move to ScriptingUtil
|
||||
public static void registerClassNameForScript(
|
||||
BindingTrace bindingTrace,
|
||||
@NotNull JetScript jetScript,
|
||||
@NotNull Type asmType
|
||||
) {
|
||||
ScriptDescriptor descriptor = bindingTrace.getBindingContext().get(SCRIPT, jetScript);
|
||||
public static void registerClassNameForScript(@NotNull BindingTrace trace, @NotNull JetScript script, @NotNull Type asmType) {
|
||||
ScriptDescriptor descriptor = trace.getBindingContext().get(SCRIPT, script);
|
||||
if (descriptor == null) {
|
||||
throw new IllegalStateException("Descriptor is not found for PSI " + jetScript);
|
||||
throw new IllegalStateException("Script descriptor is not found for PSI: " + JetPsiUtil.getElementTextWithContext(script));
|
||||
}
|
||||
registerClassNameForScript(bindingTrace, descriptor, asmType);
|
||||
|
||||
String simpleName = asmType.getInternalName().substring(asmType.getInternalName().lastIndexOf('/') + 1);
|
||||
ClassDescriptorImpl classDescriptor =
|
||||
new ClassDescriptorImpl(descriptor, Name.special("<script-" + simpleName + ">"), Modality.FINAL,
|
||||
Collections.singleton(KotlinBuiltIns.getInstance().getAnyType()), toSourceElement(script));
|
||||
classDescriptor.initialize(JetScope.EMPTY, Collections.<ConstructorDescriptor>emptySet(), null);
|
||||
|
||||
recordClosure(trace, classDescriptor, null, asmType);
|
||||
|
||||
trace.record(CLASS_FOR_SCRIPT, descriptor, classDescriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -287,73 +263,30 @@ public class CodegenBinding {
|
||||
|
||||
@NotNull
|
||||
public static Type getAsmType(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor klass) {
|
||||
klass = (ClassDescriptor) klass.getOriginal();
|
||||
Type alreadyComputedType = bindingContext.get(ASM_TYPE, klass);
|
||||
if (alreadyComputedType != null) {
|
||||
return alreadyComputedType;
|
||||
}
|
||||
|
||||
Type asmType = Type.getObjectType(getAsmTypeImpl(bindingContext, klass));
|
||||
assert PsiCodegenPredictor.checkPredictedNameFromPsi(klass, asmType);
|
||||
return asmType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getAsmTypeImpl(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor klass) {
|
||||
DeclarationDescriptor container = klass.getContainingDeclaration();
|
||||
|
||||
Name name = SpecialNames.safeIdentifier(klass.getName());
|
||||
if (container instanceof PackageFragmentDescriptor) {
|
||||
String shortName = name.getIdentifier();
|
||||
FqName fqName = ((PackageFragmentDescriptor) container).getFqName();
|
||||
return fqName.isRoot() ? shortName : fqName.asString().replace('.', '/') + '/' + shortName;
|
||||
}
|
||||
|
||||
if (container instanceof ScriptDescriptor) {
|
||||
Type scriptType = asmTypeForScriptDescriptor(bindingContext, (ScriptDescriptor) container);
|
||||
return scriptType.getInternalName() + "$" + name.getIdentifier();
|
||||
}
|
||||
|
||||
assert container instanceof ClassDescriptor : "Unexpected container: " + container + " for " + klass;
|
||||
|
||||
String containerInternalName = getAsmType(bindingContext, (ClassDescriptor) container).getInternalName();
|
||||
switch (klass.getKind()) {
|
||||
case ENUM_ENTRY:
|
||||
return containerInternalName;
|
||||
case CLASS_OBJECT:
|
||||
return containerInternalName + JvmAbi.CLASS_OBJECT_SUFFIX;
|
||||
default:
|
||||
return containerInternalName + "$" + name.getIdentifier();
|
||||
}
|
||||
Type type = bindingContext.get(ASM_TYPE, klass);
|
||||
assert type != null : "Type is not yet recorded for " + klass;
|
||||
return type;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ResolvedCall<ConstructorDescriptor> findSuperCall(
|
||||
@NotNull BindingContext bindingContext,
|
||||
@Nullable JetElement classOrObject
|
||||
@NotNull JetElement classOrObject
|
||||
) {
|
||||
if (!(classOrObject instanceof JetClassOrObject)) {
|
||||
return null;
|
||||
}
|
||||
if (!(classOrObject instanceof JetClassOrObject)) return null;
|
||||
|
||||
if (classOrObject instanceof JetClass && ((JetClass) classOrObject).isTrait()) {
|
||||
return null;
|
||||
}
|
||||
if (classOrObject instanceof JetClass && ((JetClass) classOrObject).isTrait()) return null;
|
||||
|
||||
for (JetDelegationSpecifier specifier : ((JetClassOrObject) classOrObject).getDelegationSpecifiers()) {
|
||||
if (specifier instanceof JetDelegatorToSuperCall) {
|
||||
JetType supertype = bindingContext.get(TYPE, specifier.getTypeReference());
|
||||
assert supertype != null : String.format(
|
||||
"No type in binding context for \n---\n%s\n---\n", JetPsiUtil.getElementTextWithContext(specifier));
|
||||
if (!(specifier instanceof JetDelegatorToSuperCall)) continue;
|
||||
|
||||
ClassifierDescriptor superClass = supertype.getConstructor().getDeclarationDescriptor();
|
||||
if (superClass != null && !isInterface(superClass)) {
|
||||
ResolvedCall<?> resolvedCall = getResolvedCall(specifier, bindingContext);
|
||||
if (resolvedCall != null && resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor) {
|
||||
//noinspection unchecked
|
||||
return (ResolvedCall<ConstructorDescriptor>) resolvedCall;
|
||||
}
|
||||
}
|
||||
ResolvedCall<?> resolvedCall = getResolvedCall(specifier, bindingContext);
|
||||
if (resolvedCall == null) continue;
|
||||
|
||||
CallableDescriptor constructor = resolvedCall.getResultingDescriptor();
|
||||
if (constructor instanceof ConstructorDescriptor && !isInterface(constructor.getContainingDeclaration())) {
|
||||
//noinspection unchecked
|
||||
return (ResolvedCall<ConstructorDescriptor>) resolvedCall;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,9 +317,4 @@ public class CodegenBinding {
|
||||
|
||||
return allInnerClasses;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getJvmInternalName(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor classDescriptor) {
|
||||
return getAsmType(bindingContext, classDescriptor).getClassName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.codegen.JvmCodegenUtil.getDirectMember;
|
||||
|
||||
public final class MutableClosure implements CalculatedClosure {
|
||||
private final ResolvedCall<ConstructorDescriptor> superCall;
|
||||
|
||||
@@ -40,13 +42,25 @@ public final class MutableClosure implements CalculatedClosure {
|
||||
private List<Pair<String, Type>> recordedFields;
|
||||
|
||||
MutableClosure(
|
||||
@NotNull ClassDescriptor classDescriptor,
|
||||
@Nullable ResolvedCall<ConstructorDescriptor> superCall,
|
||||
@Nullable ClassDescriptor enclosingClass,
|
||||
@Nullable CallableDescriptor enclosingReceiverDescriptor
|
||||
@Nullable ClassDescriptor enclosingClass
|
||||
) {
|
||||
this.superCall = superCall;
|
||||
this.enclosingClass = enclosingClass;
|
||||
this.enclosingReceiverDescriptor = enclosingReceiverDescriptor;
|
||||
this.superCall = superCall;
|
||||
this.enclosingReceiverDescriptor = enclosingExtensionMemberForClass(classDescriptor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static CallableDescriptor enclosingExtensionMemberForClass(@NotNull ClassDescriptor classDescriptor) {
|
||||
DeclarationDescriptor classContainer = classDescriptor.getContainingDeclaration();
|
||||
if (classContainer instanceof CallableMemberDescriptor) {
|
||||
CallableMemberDescriptor member = getDirectMember((CallableMemberDescriptor) classContainer);
|
||||
if (member.getReceiverParameter() != null) {
|
||||
return member;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -16,32 +16,18 @@
|
||||
|
||||
package org.jetbrains.jet.codegen.binding;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.codegen.AsmUtil;
|
||||
import org.jetbrains.jet.codegen.ClassBuilderFactories;
|
||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
|
||||
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
|
||||
import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
|
||||
|
||||
public final class PsiCodegenPredictor {
|
||||
@@ -82,14 +68,14 @@ public final class PsiCodegenPredictor {
|
||||
}
|
||||
}
|
||||
else {
|
||||
FqName packageFqName = declaration.getContainingJetFile().getPackageFqName();
|
||||
JetFile containingFile = declaration.getContainingJetFile();
|
||||
|
||||
if (declaration instanceof JetNamedFunction) {
|
||||
Name name = ((JetNamedFunction) declaration).getNameAsName();
|
||||
return name == null ? null : PackageClassUtils.getPackageClassInternalName(packageFqName) + "$" + name.asString();
|
||||
return name == null ? null : PackagePartClassUtils.getPackagePartInternalName(containingFile) + "$" + name.asString();
|
||||
}
|
||||
|
||||
parentInternalName = AsmUtil.internalNameByFqNameWithoutInnerClasses(packageFqName);
|
||||
parentInternalName = AsmUtil.internalNameByFqNameWithoutInnerClasses(containingFile.getPackageFqName());
|
||||
}
|
||||
|
||||
if (declaration instanceof JetClassObject) {
|
||||
@@ -128,39 +114,4 @@ public final class PsiCodegenPredictor {
|
||||
|
||||
return parentInternalName + (parentDeclaration == null ? "/" : "$") + name.asString();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JetFile getFileForPackagePartName(@NotNull Collection<JetFile> allPackageFiles, @NotNull JvmClassName className) {
|
||||
for (JetFile file : allPackageFiles) {
|
||||
String internalName = PackagePartClassUtils.getPackagePartInternalName(file);
|
||||
JvmClassName jvmClassName = JvmClassName.byInternalName(internalName);
|
||||
if (jvmClassName.equals(className)) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JetFile getFileForCodegenNamedClass(
|
||||
@NotNull ModuleDescriptor module,
|
||||
@NotNull BindingContext context,
|
||||
@NotNull Collection<JetFile> allPackageFiles,
|
||||
@NotNull String classInternalName
|
||||
) {
|
||||
Project project = allPackageFiles.iterator().next().getProject();
|
||||
GenerationState state = new GenerationState(project, ClassBuilderFactories.THROW_EXCEPTION, module, context,
|
||||
new ArrayList<JetFile>(allPackageFiles));
|
||||
state.beforeCompile();
|
||||
|
||||
BindingTrace trace = state.getBindingTrace();
|
||||
for (ClassDescriptor classDescriptor : trace.getKeys(CodegenBinding.ASM_TYPE)) {
|
||||
Type type = trace.get(CodegenBinding.ASM_TYPE, classDescriptor);
|
||||
if (type != null && classInternalName.equals(type.getInternalName())) {
|
||||
return DescriptorToSourceUtils.getContainingFile(classDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import kotlin.Function0;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.codegen.*;
|
||||
import org.jetbrains.jet.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.jet.codegen.binding.MutableClosure;
|
||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
||||
@@ -39,7 +38,8 @@ import java.util.Map;
|
||||
|
||||
import static org.jetbrains.jet.codegen.AsmUtil.CAPTURED_THIS_FIELD;
|
||||
import static org.jetbrains.jet.codegen.AsmUtil.getVisibilityAccessFlag;
|
||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
|
||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.anonymousClassForFunction;
|
||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.canHaveOuter;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PRIVATE;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PROTECTED;
|
||||
|
||||
@@ -266,13 +266,12 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
lazyOuterExpression = LockBasedStorageManager.NO_LOCKS.createNullableLazyValue(new Function0<StackValue>() {
|
||||
@Override
|
||||
public StackValue invoke() {
|
||||
BindingContext bindingContext = typeMapper.getBindingContext();
|
||||
ClassDescriptor enclosingClass = getEnclosingClass();
|
||||
return enclosingClass != null && canHaveOuter(bindingContext, classDescriptor)
|
||||
? StackValue.field(typeMapper.mapType(enclosingClass),
|
||||
CodegenBinding.getAsmType(bindingContext, classDescriptor),
|
||||
CAPTURED_THIS_FIELD,
|
||||
false)
|
||||
if (enclosingClass == null) return null;
|
||||
|
||||
return canHaveOuter(typeMapper.getBindingContext(), classDescriptor)
|
||||
? StackValue.field(typeMapper.mapType(enclosingClass), typeMapper.mapType(classDescriptor),
|
||||
CAPTURED_THIS_FIELD, false)
|
||||
: null;
|
||||
}
|
||||
});
|
||||
@@ -289,7 +288,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
|
||||
for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) {
|
||||
if (aCase.isCase(d)) {
|
||||
Type classType = state.getBindingContext().get(ASM_TYPE, getThisDescriptor());
|
||||
Type classType = state.getTypeMapper().mapType(getThisDescriptor());
|
||||
StackValue innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure, classType);
|
||||
if (innerValue == null) {
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.extensions
|
||||
|
||||
import org.jetbrains.jet.extensions.ProjectExtensionDescriptor
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.jet.codegen.StackValue
|
||||
import org.jetbrains.jet.codegen.state.JetTypeMapper
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
public trait ExpressionCodegenExtension {
|
||||
class object : ProjectExtensionDescriptor<ExpressionCodegenExtension>("org.jetbrains.kotlin.expressionCodegenExtension", javaClass<ExpressionCodegenExtension>())
|
||||
|
||||
public class Context(
|
||||
public val typeMapper: JetTypeMapper,
|
||||
public val v: InstructionAdapter
|
||||
)
|
||||
|
||||
// return null if not applicable
|
||||
public fun apply(receiver: StackValue, resolvedCall: ResolvedCall<*>, c: ExpressionCodegenExtension.Context): StackValue?
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public class AnonymousObjectTransformer {
|
||||
if (file == null) {
|
||||
throw new RuntimeException("Couldn't find virtual file for " + objectInternalName);
|
||||
}
|
||||
reader = new ClassReader(file.getInputStream());
|
||||
reader = new ClassReader(file.contentsToByteArray());
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
||||
@@ -47,18 +47,15 @@ import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
|
||||
import org.jetbrains.org.objectweb.asm.util.Textifier;
|
||||
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.jet.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.jet.codegen.inline.InlineCodegenUtil.addInlineMarker;
|
||||
|
||||
public class InlineCodegen implements CallGenerator {
|
||||
private final GenerationState state;
|
||||
@@ -130,7 +127,7 @@ public class InlineCodegen implements CallGenerator {
|
||||
throw new CompilationException("Couldn't inline method call '" +
|
||||
functionDescriptor.getName() +
|
||||
"' into \n" + (element != null ? element.getText() : "null psi element " + this.codegen.getContext().getContextDescriptor()) +
|
||||
(generateNodeText ? ("\ncause: " + getNodeText(node)) : ""),
|
||||
(generateNodeText ? ("\ncause: " + InlineCodegenUtil.getNodeText(node)) : ""),
|
||||
e, callElement);
|
||||
}
|
||||
|
||||
@@ -158,7 +155,7 @@ public class InlineCodegen implements CallGenerator {
|
||||
MethodNode node;
|
||||
if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) {
|
||||
VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable((DeserializedSimpleFunctionDescriptor) functionDescriptor, state);
|
||||
node = InlineCodegenUtil.getMethodNode(file.getInputStream(), asmMethod.getName(), asmMethod.getDescriptor());
|
||||
node = InlineCodegenUtil.getMethodNode(file.contentsToByteArray(), asmMethod.getName(), asmMethod.getDescriptor());
|
||||
|
||||
if (node == null) {
|
||||
throw new RuntimeException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor));
|
||||
@@ -208,6 +205,8 @@ public class InlineCodegen implements CallGenerator {
|
||||
//through generation captured parameters will be added to invocationParamBuilder
|
||||
putClosureParametersOnStack();
|
||||
|
||||
addInlineMarker(codegen.v, true);
|
||||
|
||||
Parameters parameters = invocationParamBuilder.buildParameters();
|
||||
|
||||
InliningContext info = new RootInliningContext(expressionMap,
|
||||
@@ -242,10 +241,13 @@ public class InlineCodegen implements CallGenerator {
|
||||
}
|
||||
}
|
||||
};
|
||||
List<MethodInliner.FinallyBlockInfo> infos = MethodInliner.processReturns(adapter, labelOwner, true, null);
|
||||
List<MethodInliner.ExternalFinallyBlockInfo> infos = MethodInliner.processReturns(adapter, labelOwner, true, null);
|
||||
generateAndInsertFinallyBlocks(adapter, infos);
|
||||
|
||||
adapter.accept(new InliningInstructionAdapter(codegen.v));
|
||||
|
||||
addInlineMarker(codegen.v, false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -443,19 +445,6 @@ public class InlineCodegen implements CallGenerator {
|
||||
return (getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) != 0;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getNodeText(@Nullable MethodNode node) {
|
||||
if (node == null) {
|
||||
return "Not generated";
|
||||
}
|
||||
Textifier p = new Textifier();
|
||||
node.accept(new TraceMethodVisitor(p));
|
||||
StringWriter sw = new StringWriter();
|
||||
p.print(new PrintWriter(sw));
|
||||
sw.flush();
|
||||
return node.name + " " + node.desc + ": \n " + sw.getBuffer().toString();
|
||||
}
|
||||
|
||||
private static String descriptorName(DeclarationDescriptor descriptor) {
|
||||
return DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor);
|
||||
}
|
||||
@@ -494,10 +483,10 @@ public class InlineCodegen implements CallGenerator {
|
||||
}
|
||||
|
||||
|
||||
public void generateAndInsertFinallyBlocks(MethodNode intoNode, List<MethodInliner.FinallyBlockInfo> insertPoints) {
|
||||
public void generateAndInsertFinallyBlocks(MethodNode intoNode, List<MethodInliner.ExternalFinallyBlockInfo> insertPoints) {
|
||||
if (!codegen.hasFinallyBlocks()) return;
|
||||
|
||||
for (MethodInliner.FinallyBlockInfo insertPoint : insertPoints) {
|
||||
for (MethodInliner.ExternalFinallyBlockInfo insertPoint : insertPoints) {
|
||||
MethodNode finallyNode = InlineCodegenUtil.createEmptyMethodNode();
|
||||
ExpressionCodegen finallyCodegen =
|
||||
new ExpressionCodegen(finallyNode, codegen.getFrameMap(), codegen.getReturnType(),
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
|
||||
package org.jetbrains.jet.codegen.inline;
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
import org.jetbrains.jet.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.jet.codegen.context.CodegenContext;
|
||||
import org.jetbrains.jet.codegen.context.PackageContext;
|
||||
@@ -35,6 +35,7 @@ import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
|
||||
import org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils;
|
||||
@@ -44,12 +45,14 @@ import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnList;
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
|
||||
import org.jetbrains.org.objectweb.asm.tree.*;
|
||||
import org.jetbrains.org.objectweb.asm.util.Textifier;
|
||||
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.ListIterator;
|
||||
|
||||
@@ -69,10 +72,13 @@ public class InlineCodegenUtil {
|
||||
public static final String NON_LOCAL_RETURN = "$$$$$NON_LOCAL_RETURN$$$$$";
|
||||
|
||||
public static final String ROOT_LABEL = "$$$$$ROOT$$$$$";
|
||||
public static final String INLINE_MARKER_CLASS_NAME = "kotlin/jvm/internal/InlineMarker";
|
||||
public static final String INLINE_MARKER_BEFORE_METHOD_NAME = "beforeInlineCall";
|
||||
public static final String INLINE_MARKER_AFTER_METHOD_NAME = "afterInlineCall";
|
||||
|
||||
@Nullable
|
||||
public static MethodNode getMethodNode(
|
||||
InputStream classData,
|
||||
byte[] classData,
|
||||
final String methodName,
|
||||
final String methodDescriptor
|
||||
) throws ClassNotFoundException, IOException {
|
||||
@@ -254,8 +260,8 @@ public class InlineCodegenUtil {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static MaxCalcNode wrapWithMaxLocalCalc(@NotNull MethodNode methodNode) {
|
||||
return new MaxCalcNode(methodNode);
|
||||
public static MethodVisitor wrapWithMaxLocalCalc(@NotNull MethodNode methodNode) {
|
||||
return new MaxStackFrameSizeAndLocalsCalculator(API, methodNode.access, methodNode.desc, methodNode);
|
||||
}
|
||||
|
||||
private static boolean isInteger(@NotNull String string) {
|
||||
@@ -283,6 +289,13 @@ public class InlineCodegenUtil {
|
||||
return opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN;
|
||||
}
|
||||
|
||||
//marked return could be either non-local or local in case of labeled lambda self-returns
|
||||
public static boolean isMarkedReturn(@NotNull AbstractInsnNode returnIns) {
|
||||
assert isReturnOpcode(returnIns.getOpcode()) : "Should be called on return instruction, but " + returnIns;
|
||||
AbstractInsnNode globalFlag = returnIns.getPrevious();
|
||||
return globalFlag instanceof MethodInsnNode && NON_LOCAL_RETURN.equals(((MethodInsnNode)globalFlag).owner);
|
||||
}
|
||||
|
||||
public static void generateGlobalReturnFlag(@NotNull InstructionAdapter iv, @NotNull String labelName) {
|
||||
iv.invokestatic(NON_LOCAL_RETURN, labelName, "()V", false);
|
||||
}
|
||||
@@ -294,16 +307,16 @@ public class InlineCodegenUtil {
|
||||
case Opcodes.DRETURN: return Type.DOUBLE_TYPE;
|
||||
case Opcodes.FRETURN: return Type.FLOAT_TYPE;
|
||||
case Opcodes.LRETURN: return Type.LONG_TYPE;
|
||||
default: return Type.getObjectType("object");
|
||||
default: return AsmTypeConstants.OBJECT_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
public static void insertNodeBefore(@NotNull MethodNode from, @NotNull MethodNode to, @NotNull AbstractInsnNode afterNode) {
|
||||
public static void insertNodeBefore(@NotNull MethodNode from, @NotNull MethodNode to, @NotNull AbstractInsnNode beforeNode) {
|
||||
InsnList instructions = to.instructions;
|
||||
ListIterator<AbstractInsnNode> iterator = from.instructions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
AbstractInsnNode next = iterator.next();
|
||||
instructions.insertBefore(afterNode, next);
|
||||
instructions.insertBefore(beforeNode, next);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,4 +324,69 @@ public class InlineCodegenUtil {
|
||||
public static MethodNode createEmptyMethodNode() {
|
||||
return new MethodNode(API, 0, "fake", "()V", null, null);
|
||||
}
|
||||
|
||||
private static boolean isLastGoto(@NotNull AbstractInsnNode insnNode, @NotNull AbstractInsnNode stopAt) {
|
||||
if (insnNode.getOpcode() == Opcodes.GOTO) {
|
||||
insnNode = insnNode.getNext();
|
||||
while (insnNode != stopAt && isLineNumberOrLabel(insnNode)) {
|
||||
insnNode = insnNode.getNext();
|
||||
}
|
||||
return stopAt == insnNode;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean isLineNumberOrLabel(@Nullable AbstractInsnNode node) {
|
||||
return node instanceof LineNumberNode || node instanceof LabelNode;
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public static LabelNode firstLabelInChain(@NotNull LabelNode node) {
|
||||
LabelNode curNode = node;
|
||||
while (curNode.getPrevious() instanceof LabelNode) {
|
||||
curNode = (LabelNode) curNode.getPrevious();
|
||||
}
|
||||
return curNode;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getNodeText(@Nullable MethodNode node) {
|
||||
return getNodeText(node, new Textifier());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getNodeText(@Nullable MethodNode node, @NotNull Textifier textifier) {
|
||||
if (node == null) {
|
||||
return "Not generated";
|
||||
}
|
||||
node.accept(new TraceMethodVisitor(textifier));
|
||||
StringWriter sw = new StringWriter();
|
||||
textifier.print(new PrintWriter(sw));
|
||||
sw.flush();
|
||||
return node.name + " " + node.desc + ": \n " + sw.getBuffer().toString();
|
||||
}
|
||||
|
||||
public static class LabelTextifier extends Textifier {
|
||||
|
||||
public LabelTextifier() {
|
||||
super(API);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@TestOnly
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public String getLabelNameIfExists(@NotNull Label l) {
|
||||
return labelNames == null ? null : labelNames.get(l);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addInlineMarker(
|
||||
@NotNull InstructionAdapter v,
|
||||
boolean isStartNotEnd
|
||||
) {
|
||||
v.visitMethodInsn(Opcodes.INVOKESTATIC, INLINE_MARKER_CLASS_NAME,
|
||||
(isStartNotEnd ? INLINE_MARKER_BEFORE_METHOD_NAME : INLINE_MARKER_AFTER_METHOD_NAME),
|
||||
"()V", false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,547 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.inline;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.LinkedListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.util.containers.Stack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.codegen.AsmUtil;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
import org.jetbrains.org.objectweb.asm.tree.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.codegen.inline.InlineCodegenUtil.*;
|
||||
|
||||
public class InternalFinallyBlockInliner {
|
||||
|
||||
private static class FinallyBlockInfo {
|
||||
|
||||
final AbstractInsnNode startIns;
|
||||
|
||||
final AbstractInsnNode endInsExclusive;
|
||||
|
||||
private FinallyBlockInfo(@NotNull AbstractInsnNode inclusiveStart, @NotNull AbstractInsnNode exclusiveEnd) {
|
||||
startIns = inclusiveStart;
|
||||
endInsExclusive = exclusiveEnd;
|
||||
}
|
||||
}
|
||||
|
||||
public static void processInlineFunFinallyBlocks(@NotNull MethodNode inlineFun, int lambdaTryCatchBlockNodes) {
|
||||
int index = 0;
|
||||
List<TryCatchBlockNodeInfo> inlineFunTryBlockInfo = new ArrayList<TryCatchBlockNodeInfo>();
|
||||
for (TryCatchBlockNode block : inlineFun.tryCatchBlocks) {
|
||||
inlineFunTryBlockInfo.add(new TryCatchBlockNodeInfo(block, index++ < lambdaTryCatchBlockNodes));
|
||||
}
|
||||
|
||||
if (hasFinallyBlocks(inlineFunTryBlockInfo)) {
|
||||
new InternalFinallyBlockInliner(inlineFun, inlineFunTryBlockInfo).processInlineFunFinallyBlocks();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final MethodNode inlineFun;
|
||||
|
||||
private final List<TryCatchBlockNodeInfo> inlineFunTryBlockInfo;
|
||||
|
||||
private final ListMultimap<LabelNode, TryCatchBlockNodeInfo> tryBlockStarts = LinkedListMultimap.create();
|
||||
|
||||
private final ListMultimap<LabelNode, TryCatchBlockNodeInfo> tryBlockEnds = LinkedListMultimap.create();
|
||||
|
||||
//lambdaTryCatchBlockNodes is number of TryCatchBlockNodes that was inlined with lambdas into function
|
||||
//due to code generation specific they placed before function TryCatchBlockNodes
|
||||
private InternalFinallyBlockInliner(@NotNull MethodNode inlineFun, List<TryCatchBlockNodeInfo> inlineFunTryBlockInfo) {
|
||||
this.inlineFun = inlineFun;
|
||||
this.inlineFunTryBlockInfo = inlineFunTryBlockInfo;
|
||||
}
|
||||
|
||||
private int initAndGetVarIndexForNonLocalReturnValue() {
|
||||
//sortTryCatchBlocks();/*TODO maybe remove*/
|
||||
mapLabelsToTryCatchBlocks();
|
||||
|
||||
MaxLocalsCalculator tempCalcNode = new MaxLocalsCalculator(
|
||||
InlineCodegenUtil.API,
|
||||
inlineFun.access, inlineFun.desc, null
|
||||
);
|
||||
inlineFun.accept(tempCalcNode);
|
||||
return tempCalcNode.getMaxLocals();
|
||||
}
|
||||
|
||||
private void processInlineFunFinallyBlocks() {
|
||||
int nextTempNonLocalVarIndex = initAndGetVarIndexForNonLocalReturnValue();
|
||||
|
||||
Stack<TryCatchBlockNodeInfo> coveringTryCatchBlocks = new Stack<TryCatchBlockNodeInfo>();
|
||||
InsnList instructions = inlineFun.instructions;
|
||||
|
||||
//As we do finally block code search after non-local return instruction
|
||||
// we should be sure that all others non-local returns already processed in this finally block.
|
||||
// So we do instruction processing in reverse order!
|
||||
AbstractInsnNode curIns = instructions.getLast();
|
||||
while (curIns != null) {
|
||||
updateCoveringTryBlocks(coveringTryCatchBlocks, curIns);
|
||||
|
||||
//At this point only global return is possible, local one already substituted with: goto endLabel
|
||||
if (!InlineCodegenUtil.isReturnOpcode(curIns.getOpcode()) || !InlineCodegenUtil.isMarkedReturn(curIns)) {
|
||||
curIns = curIns.getPrevious();
|
||||
continue;
|
||||
}
|
||||
|
||||
AbstractInsnNode instrInsertFinallyBefore = curIns.getPrevious();
|
||||
AbstractInsnNode nextPrev = instrInsertFinallyBefore.getPrevious();
|
||||
Type nonLocalReturnType = InlineCodegenUtil.getReturnType(curIns.getOpcode());
|
||||
|
||||
//Generally there could be several tryCatch blocks (group) on one code interval (same start and end labels, but maybe different handlers) -
|
||||
// all of them refer to one try/*catches*/finally or try/catches.
|
||||
// Each group that corresponds to try/*catches*/finally contains tryCatch block with default handler.
|
||||
// For each such group we should insert corresponding finally before non-local return.
|
||||
// So we split all try blocks on current instructions to groups and process them independently
|
||||
List<TryBlockCluster<TryCatchBlockNodeInfo>> clusters = InlinePackage.doClustering(coveringTryCatchBlocks);
|
||||
ListIterator<TryBlockCluster<TryCatchBlockNodeInfo>> tryCatchBlockIterator = clusters.listIterator(clusters.size());
|
||||
//Reverse visiting cause innermost tryCatchBlocks in the end
|
||||
while (tryCatchBlockIterator.hasPrevious()) {
|
||||
TryBlockCluster originalFinallyCluster = tryCatchBlockIterator.previous();
|
||||
List<TryCatchBlockNodeInfo> clusterBlocks = originalFinallyCluster.getBlocks();
|
||||
TryCatchBlockNodeInfo originalFinallyBlock = clusterBlocks.get(0);
|
||||
|
||||
FinallyBlockInfo finallyInfo = findFinallyBlockBody(originalFinallyBlock, inlineFunTryBlockInfo);
|
||||
if (finallyInfo == null) continue;
|
||||
|
||||
instructions.resetLabels();
|
||||
|
||||
List<TryCatchBlockNodePosition> tryCatchBlockInlinedInFinally = findTryCatchBlocksInlinedInFinally(finallyInfo);
|
||||
|
||||
//Keep some information about label nodes, we need it to understand whether it's jump inside finally block or outside
|
||||
// in first case we do call VISIT on instruction otherwise recreating jump instruction (see below)
|
||||
Set<LabelNode> labelsInsideFinally = rememberOriginalLabelNodes(finallyInfo);
|
||||
|
||||
//Creating temp node for finally block copy with some additional instruction
|
||||
MethodNode finallyBlockCopy = createEmptyMethodNode();
|
||||
Label newFinallyStart = new Label();
|
||||
Label newFinallyEnd = new Label();
|
||||
Label insertedBlockEnd = new Label();
|
||||
|
||||
if (nonLocalReturnType != Type.VOID_TYPE) {
|
||||
finallyBlockCopy.visitVarInsn(nonLocalReturnType.getOpcode(Opcodes.ISTORE), nextTempNonLocalVarIndex);
|
||||
}
|
||||
finallyBlockCopy.visitLabel(newFinallyStart);
|
||||
|
||||
//Writing finally block body to temporary node
|
||||
AbstractInsnNode currentIns = finallyInfo.startIns;
|
||||
while (currentIns != finallyInfo.endInsExclusive) {
|
||||
//This condition allows another model for non-local returns processing
|
||||
if (false && InlineCodegenUtil.isReturnOpcode(currentIns.getOpcode()) && !InlineCodegenUtil.isMarkedReturn(currentIns)) {
|
||||
//substitute all local returns in finally finallyInfo with non-local one lambdaFinallyBlocks try finallyInfo
|
||||
//TODO same for jumps
|
||||
Type localReturnType = InlineCodegenUtil.getReturnType(currentIns.getOpcode());
|
||||
substituteReturnValueInFinally(nextTempNonLocalVarIndex, nonLocalReturnType, finallyBlockCopy,
|
||||
localReturnType, true);
|
||||
|
||||
instrInsertFinallyBefore.accept(finallyBlockCopy);
|
||||
curIns.accept(finallyBlockCopy);
|
||||
}
|
||||
else {
|
||||
boolean isInsOrJumpInsideFinally =
|
||||
!(currentIns instanceof JumpInsnNode) ||
|
||||
labelsInsideFinally.contains(((JumpInsnNode) currentIns).label);
|
||||
|
||||
if (isInsOrJumpInsideFinally) {
|
||||
currentIns.accept(finallyBlockCopy); //VISIT
|
||||
}
|
||||
else {
|
||||
//keep original jump: add currentIns clone
|
||||
finallyBlockCopy.instructions.add(new JumpInsnNode(currentIns.getOpcode(), ((JumpInsnNode) currentIns).label));
|
||||
}
|
||||
}
|
||||
|
||||
currentIns = currentIns.getNext();
|
||||
}
|
||||
|
||||
finallyBlockCopy.visitLabel(newFinallyEnd);
|
||||
if (nonLocalReturnType != Type.VOID_TYPE) {
|
||||
finallyBlockCopy.visitVarInsn(nonLocalReturnType.getOpcode(Opcodes.ILOAD), nextTempNonLocalVarIndex);
|
||||
nextTempNonLocalVarIndex += nonLocalReturnType.getSize(); //TODO: do more wise indexing
|
||||
}
|
||||
|
||||
finallyBlockCopy.visitLabel(insertedBlockEnd);
|
||||
|
||||
//Copying finally body before non-local return instruction
|
||||
InlineCodegenUtil.insertNodeBefore(finallyBlockCopy, inlineFun, instrInsertFinallyBefore);
|
||||
|
||||
nextPrev = updateExceptionTable(coveringTryCatchBlocks, nextPrev, clusterBlocks, newFinallyStart, newFinallyEnd,
|
||||
tryCatchBlockInlinedInFinally, labelsInsideFinally, (LabelNode) insertedBlockEnd.info);
|
||||
}
|
||||
curIns = nextPrev;
|
||||
}
|
||||
|
||||
inlineFun.tryCatchBlocks.clear();
|
||||
for (TryCatchBlockNodeInfo info : inlineFunTryBlockInfo) {
|
||||
inlineFun.tryCatchBlocks.add(info.getNode());
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Set<LabelNode> rememberOriginalLabelNodes(@NotNull FinallyBlockInfo finallyInfo) {
|
||||
Set<LabelNode> labelsInsideFinally = new HashSet<LabelNode>();
|
||||
for (AbstractInsnNode currentIns = finallyInfo.startIns; currentIns != finallyInfo.endInsExclusive; currentIns = currentIns.getNext()) {
|
||||
if (currentIns instanceof LabelNode) {
|
||||
labelsInsideFinally.add((LabelNode) currentIns);
|
||||
}
|
||||
}
|
||||
return labelsInsideFinally;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private AbstractInsnNode updateExceptionTable(
|
||||
@NotNull Stack<TryCatchBlockNodeInfo> coveringTryBlocks,
|
||||
@Nullable AbstractInsnNode nextPrev,
|
||||
@NotNull List<TryCatchBlockNodeInfo> updatingClusterBlocks,
|
||||
@NotNull Label newFinallyStart,
|
||||
@NotNull Label newFinallyEnd,
|
||||
@NotNull List<TryCatchBlockNodePosition> tryCatchBlockPresentInFinally,
|
||||
@NotNull Set<LabelNode> labelsInsideFinally,
|
||||
@NotNull LabelNode insertedBlockEnd
|
||||
|
||||
) {
|
||||
|
||||
//copy tryCatchFinallies that totally in finally block
|
||||
List<TryBlockCluster<TryCatchBlockNodePosition>> clusters = InlinePackage.doClustering(tryCatchBlockPresentInFinally);
|
||||
Map<LabelNode, TryBlockCluster<TryCatchBlockNodePosition>> handler2Cluster = new HashMap<LabelNode, TryBlockCluster<TryCatchBlockNodePosition>>();
|
||||
|
||||
for (TryBlockCluster<TryCatchBlockNodePosition> cluster : clusters) {
|
||||
List<TryCatchBlockNodePosition> clusterBlocks = cluster.getBlocks();
|
||||
TryCatchBlockNodePosition block0 = clusterBlocks.get(0);
|
||||
TryCatchPosition clusterPosition = block0.getPosition();
|
||||
if (clusterPosition == TryCatchPosition.INNER) {
|
||||
for (TryCatchBlockNodePosition position : clusterBlocks) {
|
||||
assert clusterPosition == position.getPosition() : "Wrong inner tryCatchBlock structure";
|
||||
TryCatchBlockNode tryCatchBlockNode = position.getNodeInfo().getNode();
|
||||
|
||||
assert inlineFun.instructions.indexOf(tryCatchBlockNode.start) <= inlineFun.instructions.indexOf(tryCatchBlockNode.end);
|
||||
|
||||
TryCatchBlockNode additionalTryCatchBlock =
|
||||
new TryCatchBlockNode((LabelNode) tryCatchBlockNode.start.getLabel().info,
|
||||
(LabelNode) tryCatchBlockNode.end.getLabel().info,
|
||||
getNewOrOldLabel(tryCatchBlockNode.handler, labelsInsideFinally),
|
||||
tryCatchBlockNode.type);
|
||||
|
||||
|
||||
assert inlineFun.instructions.indexOf(additionalTryCatchBlock.start) <= inlineFun.instructions.indexOf(additionalTryCatchBlock.end);
|
||||
|
||||
TryCatchBlockNodeInfo newInfo = new TryCatchBlockNodeInfo(additionalTryCatchBlock, true);
|
||||
tryBlockStarts.put(newInfo.getStartLabel(), newInfo);
|
||||
tryBlockEnds.put(newInfo.getEndLabel(), newInfo);
|
||||
inlineFunTryBlockInfo.add(newInfo);
|
||||
}
|
||||
}
|
||||
else if (clusterPosition == TryCatchPosition.END) {
|
||||
TryCatchBlockNodePosition defaultHandler = cluster.getDefaultHandler();
|
||||
assert defaultHandler != null : "Default handler should be present";
|
||||
handler2Cluster.put(defaultHandler.getHandler(), cluster);
|
||||
}
|
||||
else {
|
||||
assert clusterPosition == TryCatchPosition.START;
|
||||
TryCatchBlockNodePosition defaultHandler = cluster.getDefaultHandler();
|
||||
assert defaultHandler != null : "Default handler should be present";
|
||||
TryBlockCluster<TryCatchBlockNodePosition> endCluster = handler2Cluster.remove(defaultHandler.getHandler());
|
||||
assert endCluster != null : "Could find start cluster for " + clusterPosition;
|
||||
|
||||
//at this point only external finallies could occurs
|
||||
//they don't collision with updatingClusterBlocks, but may with external ones on next updateExceptionTable invocation
|
||||
Iterator<TryCatchBlockNodePosition> startBlockPositions = clusterBlocks.iterator();
|
||||
for (TryCatchBlockNodePosition endBlockPosition : endCluster.getBlocks()) {
|
||||
TryCatchBlockNodeInfo startNode = startBlockPositions.next().getNodeInfo();
|
||||
TryCatchBlockNodeInfo endNode = endBlockPosition.getNodeInfo();
|
||||
|
||||
assert Objects.equal(startNode.getType(), endNode.getType()) : "Different handler types : " + startNode.getType() + " " + endNode.getType();
|
||||
|
||||
patchTryBlocks((LabelNode) startNode.getStartLabel().getLabel().info, endNode, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (handler2Cluster.size() == 1) {
|
||||
TryBlockCluster<TryCatchBlockNodePosition> singleCluster = handler2Cluster.values().iterator().next();
|
||||
if (singleCluster.getBlocks().get(0).getPosition() == TryCatchPosition.END) {
|
||||
//Pair that starts on default handler don't added to tryCatchBlockPresentInFinally cause it's out of finally block
|
||||
//TODO rewrite to clusters
|
||||
for (TryCatchBlockNodePosition endBlockPosition : singleCluster.getBlocks()) {
|
||||
TryCatchBlockNodeInfo endNode = endBlockPosition.getNodeInfo();
|
||||
patchTryBlocks((LabelNode) insertedBlockEnd.getLabel().info, endNode, true);
|
||||
//nextPrev = (AbstractInsnNode) insertedBlockEnd.getLabel().info;
|
||||
}
|
||||
|
||||
handler2Cluster.clear();
|
||||
}
|
||||
}
|
||||
assert handler2Cluster.isEmpty() : "Unmatched clusters " + handler2Cluster.size();
|
||||
|
||||
// Inserted finally shouldn't be handled by corresponding catches,
|
||||
// so we should split original interval by inserted finally one
|
||||
for (TryCatchBlockNodeInfo block : updatingClusterBlocks) {
|
||||
//update exception mapping
|
||||
LabelNode oldStartNode = block.getNode().start;
|
||||
tryBlockStarts.remove(oldStartNode, block);
|
||||
block.getNode().start = (LabelNode) newFinallyEnd.info;
|
||||
//tryBlockStarts.put(block.getStartLabel(), block);
|
||||
|
||||
TryCatchBlockNode additionalTryCatchBlock =
|
||||
new TryCatchBlockNode(oldStartNode, (LabelNode) newFinallyStart.info, block.getNode().handler, block.getNode().type);
|
||||
|
||||
TryCatchBlockNodeInfo newInfo = new TryCatchBlockNodeInfo(additionalTryCatchBlock, false);
|
||||
tryBlockStarts.put(additionalTryCatchBlock.start, newInfo);
|
||||
tryBlockEnds.put(additionalTryCatchBlock.end, newInfo);
|
||||
|
||||
inlineFunTryBlockInfo.add(newInfo);
|
||||
|
||||
//TODO add assert
|
||||
nextPrev = additionalTryCatchBlock.end;
|
||||
coveringTryBlocks.pop();
|
||||
}
|
||||
sortTryCatchBlocks(inlineFunTryBlockInfo);
|
||||
return nextPrev;
|
||||
}
|
||||
|
||||
private void patchTryBlocks(@NotNull LabelNode newStartLabelNode, @NotNull TryCatchBlockNodeInfo endNode, boolean sort) {
|
||||
LabelNode oldStart = endNode.getStartLabel();
|
||||
endNode.getNode().start = newStartLabelNode;
|
||||
tryBlockStarts.remove(oldStart, endNode);
|
||||
tryBlockStarts.put(endNode.getNode().start, endNode);
|
||||
|
||||
|
||||
TryCatchBlockNode endTryBlock = endNode.getNode();
|
||||
TryCatchBlockNode additionalTryCatchBlock =
|
||||
new TryCatchBlockNode(oldStart,
|
||||
(LabelNode) endTryBlock.end.getLabel().info,
|
||||
endTryBlock.handler,
|
||||
endTryBlock.type);
|
||||
|
||||
TryCatchBlockNodeInfo newInfo = new TryCatchBlockNodeInfo(additionalTryCatchBlock, endNode.getOnlyCopyNotProcess());
|
||||
tryBlockStarts.put(newInfo.getStartLabel(), newInfo);
|
||||
tryBlockEnds.put(newInfo.getEndLabel(), newInfo);
|
||||
|
||||
inlineFunTryBlockInfo.add(newInfo);
|
||||
}
|
||||
|
||||
private static LabelNode getNewOrOldLabel(LabelNode oldHandler, @NotNull Set<LabelNode> labelsInsideFinally) {
|
||||
if (labelsInsideFinally.contains(oldHandler)) {
|
||||
return (LabelNode) oldHandler.getLabel().info;
|
||||
}
|
||||
|
||||
return oldHandler;
|
||||
}
|
||||
|
||||
//Keep information about try blocks that cover current instruction -
|
||||
// pushing and popping it to stack entering and exiting tryCatchBlock start and end labels
|
||||
private void updateCoveringTryBlocks(Stack<TryCatchBlockNodeInfo> coveringTryBlocks, AbstractInsnNode curIns) {
|
||||
if (!(curIns instanceof LabelNode)) return;
|
||||
|
||||
List<TryCatchBlockNodeInfo> infos = tryBlockStarts.get((LabelNode) curIns);
|
||||
for (TryCatchBlockNodeInfo startNode : infos) {
|
||||
if (!startNode.getOnlyCopyNotProcess()) {
|
||||
TryCatchBlockNodeInfo pop = coveringTryBlocks.pop();
|
||||
//Temporary disabled cause during patched structure of exceptions changed
|
||||
//assert startNode == pop : "Wrong try-catch structure " + startNode + " " + pop + " " + infos.size();
|
||||
}
|
||||
}
|
||||
|
||||
//Reversing list order cause we should pop external block before internal one
|
||||
// (originally internal blocks goes before external one, such invariant preserved via sortTryCatchBlocks method)
|
||||
for (TryCatchBlockNodeInfo info : Lists.reverse(tryBlockEnds.get((LabelNode) curIns))) {
|
||||
if (!info.getOnlyCopyNotProcess()) {
|
||||
coveringTryBlocks.add(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasFinallyBlocks(List<TryCatchBlockNodeInfo> inlineFunTryBlockInfo) {
|
||||
for (TryCatchBlockNodeInfo block : inlineFunTryBlockInfo) {
|
||||
if (!block.getOnlyCopyNotProcess() && block.getNode().type == null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void mapLabelsToTryCatchBlocks() {
|
||||
for (TryCatchBlockNodeInfo block : inlineFunTryBlockInfo) {
|
||||
tryBlockStarts.put(block.getNode().start, block);
|
||||
tryBlockEnds.put(block.getNode().end, block);
|
||||
}
|
||||
}
|
||||
|
||||
//As described above all tryCatch group that have finally block also should contains tryCatchBlockNode with default handler.
|
||||
//So we assume that instructions between end of tryCatchBlock and start of next tryCatchBlock with same default handler is required finally body.
|
||||
//There is at least two tryCatchBlockNodes in list cause there is always tryCatchBlockNode on first instruction of default handler:
|
||||
// "ASTORE defaultHandlerExceptionIndex" (handles itself, as does java).
|
||||
@Nullable
|
||||
private FinallyBlockInfo findFinallyBlockBody(
|
||||
@NotNull TryCatchBlockNodeInfo tryCatchBlock,
|
||||
@NotNull List<TryCatchBlockNodeInfo> tryCatchBlocks
|
||||
) {
|
||||
List<TryCatchBlockNodeInfo> sameDefaultHandler = new ArrayList<TryCatchBlockNodeInfo>();
|
||||
LabelNode defaultHandler = null;
|
||||
boolean afterStartBlock = false;
|
||||
for (TryCatchBlockNodeInfo block : tryCatchBlocks) {
|
||||
if (tryCatchBlock == block) {
|
||||
afterStartBlock = true;
|
||||
}
|
||||
|
||||
if (afterStartBlock) {
|
||||
if (block.getNode().type == null && (firstLabelInChain(tryCatchBlock.getNode().start) == firstLabelInChain(block.getNode().start) &&
|
||||
firstLabelInChain(tryCatchBlock.getNode().end) == firstLabelInChain(block.getNode().end)
|
||||
|| defaultHandler == firstLabelInChain(block.getNode().handler))) {
|
||||
sameDefaultHandler.add(block); //first is tryCatchBlock if no catch clauses
|
||||
if (defaultHandler == null) {
|
||||
defaultHandler = firstLabelInChain(block.getNode().handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sameDefaultHandler.isEmpty()) {
|
||||
//there is no finally block
|
||||
//it always should be present in default handler
|
||||
return null;
|
||||
}
|
||||
|
||||
TryCatchBlockNodeInfo nextIntervalWithSameDefaultHandler = sameDefaultHandler.get(1);
|
||||
AbstractInsnNode startFinallyChain = tryCatchBlock.getNode().end;
|
||||
AbstractInsnNode endFinallyChainExclusive = skipLastGotoIfNeeded(nextIntervalWithSameDefaultHandler.getNode().handler,
|
||||
nextIntervalWithSameDefaultHandler.getNode().start);
|
||||
|
||||
return new FinallyBlockInfo(startFinallyChain.getNext(), endFinallyChainExclusive);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private AbstractInsnNode skipLastGotoIfNeeded(
|
||||
@NotNull LabelNode defaultHandlerStartLabel,
|
||||
@NotNull AbstractInsnNode lastFinallyInsExclusive
|
||||
) {
|
||||
|
||||
AbstractInsnNode prevLast = getPrevNoLineNumberOrLabel(lastFinallyInsExclusive, true);
|
||||
assert prevLast != null : "Empty finally block: " + lastFinallyInsExclusive;
|
||||
|
||||
if (prevLast.getOpcode() == Opcodes.GOTO) {
|
||||
//There we should understand whether goto is jump over catches or last break/continue command inside finally.
|
||||
//If it's a jump over catches so next is true:
|
||||
// 1. jump label should go after default catch handler start label
|
||||
// AND
|
||||
// 2. it shouldn't be present in default catch block, otherwise it break/continue
|
||||
LabelNode targetJump = ((JumpInsnNode) prevLast).label;
|
||||
|
||||
InsnList instructions = inlineFun.instructions;
|
||||
if (instructions.indexOf(defaultHandlerStartLabel) < instructions.indexOf(targetJump)) { //1 condition
|
||||
AbstractInsnNode cur = defaultHandlerStartLabel;
|
||||
while (cur != targetJump) {
|
||||
if (cur.getOpcode() == Opcodes.GOTO) {
|
||||
//noinspection ConstantConditions
|
||||
if (((JumpInsnNode) cur).label == targetJump) { //fail of 2 condition
|
||||
return lastFinallyInsExclusive;
|
||||
}
|
||||
}
|
||||
cur = cur.getNext();
|
||||
}
|
||||
|
||||
return prevLast;
|
||||
}
|
||||
}
|
||||
return lastFinallyInsExclusive;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<TryCatchBlockNodePosition> findTryCatchBlocksInlinedInFinally(@NotNull FinallyBlockInfo finallyInfo) {
|
||||
List<TryCatchBlockNodePosition> result = new ArrayList<TryCatchBlockNodePosition>();
|
||||
Map<TryCatchBlockNodeInfo, TryCatchBlockNodePosition> processedBlocks = new HashMap<TryCatchBlockNodeInfo, TryCatchBlockNodePosition>();
|
||||
for (AbstractInsnNode curInstr = finallyInfo.startIns; curInstr != finallyInfo.endInsExclusive; curInstr = curInstr.getNext()) {
|
||||
if (!(curInstr instanceof LabelNode)) continue;
|
||||
|
||||
LabelNode curLabel = (LabelNode) curInstr;
|
||||
List<TryCatchBlockNodeInfo> startedTryBlocks = tryBlockStarts.get(curLabel);
|
||||
if (startedTryBlocks != null) {
|
||||
for (TryCatchBlockNodeInfo block : startedTryBlocks) {
|
||||
assert !processedBlocks.containsKey(block) : "Try catch block already processed before start label!!! " + block;
|
||||
TryCatchBlockNodePosition info = new TryCatchBlockNodePosition(block, TryCatchPosition.START);
|
||||
processedBlocks.put(block, info);
|
||||
result.add(info);
|
||||
}
|
||||
}
|
||||
|
||||
List<TryCatchBlockNodeInfo> endedTryBlocks = tryBlockEnds.get(curLabel);
|
||||
if (endedTryBlocks == null) continue;
|
||||
|
||||
for (TryCatchBlockNodeInfo block : endedTryBlocks) {
|
||||
TryCatchBlockNodePosition info = processedBlocks.get(block);
|
||||
if (info != null) {
|
||||
assert info.getPosition() == TryCatchPosition.START;
|
||||
info.setPosition(TryCatchPosition.INNER);
|
||||
}
|
||||
else {
|
||||
info = new TryCatchBlockNodePosition(block, TryCatchPosition.END);
|
||||
processedBlocks.put(block, info);
|
||||
result.add(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void substituteReturnValueInFinally(
|
||||
int nonLocalVarIndex,
|
||||
@NotNull Type nonLocalReturnType,
|
||||
@NotNull MethodNode finallyBlockCopy,
|
||||
@NotNull Type localReturnType,
|
||||
boolean doPop
|
||||
) {
|
||||
if (doPop && localReturnType != Type.VOID_TYPE) {
|
||||
AsmUtil.pop(finallyBlockCopy, localReturnType);
|
||||
}
|
||||
if (nonLocalReturnType != Type.VOID_TYPE) {
|
||||
finallyBlockCopy.visitVarInsn(nonLocalReturnType.getOpcode(Opcodes.ILOAD), nonLocalVarIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static AbstractInsnNode getPrevNoLineNumberOrLabel(@NotNull AbstractInsnNode node, boolean strict) {
|
||||
AbstractInsnNode result = strict ? node.getPrevious() : node;
|
||||
while (isLineNumberOrLabel(result)) {
|
||||
result = result.getPrevious();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void sortTryCatchBlocks(@NotNull List<TryCatchBlockNodeInfo> inlineFunTryBlockInfo) {
|
||||
Comparator<TryCatchBlockNodeInfo> comp = new Comparator<TryCatchBlockNodeInfo>() {
|
||||
@Override
|
||||
public int compare(@NotNull TryCatchBlockNodeInfo t1, @NotNull TryCatchBlockNodeInfo t2) {
|
||||
int result = inlineFun.instructions.indexOf(t1.getNode().handler) - inlineFun.instructions.indexOf(t2.getNode().handler);
|
||||
if (result == 0) {
|
||||
result = inlineFun.instructions.indexOf(t1.getNode().start) - inlineFun.instructions.indexOf(t2.getNode().start);
|
||||
if (result == 0) {
|
||||
assert false : "Error: support multicatch finallies!";
|
||||
result = inlineFun.instructions.indexOf(t1.getNode().end) - inlineFun.instructions.indexOf(t2.getNode().end);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
Collections.sort(inlineFunTryBlockInfo, comp);
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.inline;
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
public class MaxCalcNode extends MethodVisitor {
|
||||
|
||||
private int maxLocal;
|
||||
|
||||
private final MethodNode node;
|
||||
|
||||
public MaxCalcNode(MethodNode node) {
|
||||
super(InlineCodegenUtil.API, node);
|
||||
this.node = node;
|
||||
int paramsSize = (node.access & Opcodes.ACC_STATIC) == 0 ? 1 : 0;
|
||||
|
||||
Type[] types = Type.getArgumentTypes(node.desc);
|
||||
for (Type type : types) {
|
||||
paramsSize += type.getSize();
|
||||
}
|
||||
maxLocal = paramsSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(int opcode, int var) {
|
||||
super.visitVarInsn(opcode, var);
|
||||
int size = opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE ? 2 : 1;
|
||||
updateMaxLocal(var, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIincInsn(int var, int increment) {
|
||||
super.visitIincInsn(var, increment);
|
||||
updateMaxLocal(var, 1);
|
||||
}
|
||||
|
||||
private void updateMaxLocal(int index, int size) {
|
||||
maxLocal = Math.max(maxLocal, index + size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(int maxStack, int maxLocals) {
|
||||
//NB: it's hack for fast maxStack calculation cause it performed only in MethodWriter
|
||||
//temporary solution: maxStack = instruction size (without labels and line numbers) * 2 (cause 1 instruction could put value of size 2)
|
||||
int size = 0;
|
||||
ListIterator<AbstractInsnNode> iterator = node.instructions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
AbstractInsnNode next = iterator.next();
|
||||
int type = next.getType();
|
||||
if (type != AbstractInsnNode.LINE && type != AbstractInsnNode.LABEL) {
|
||||
size++;
|
||||
}
|
||||
}
|
||||
super.visitMaxs(Math.max(size * 2, maxStack), Math.max(maxLocals, this.maxLocal));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.inline;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
public class MaxLocalsCalculator extends MethodVisitor {
|
||||
|
||||
private int maxLocals;
|
||||
|
||||
public MaxLocalsCalculator(int api, int access, String descriptor, MethodVisitor mv) {
|
||||
super(api, mv);
|
||||
|
||||
// updates maxLocals
|
||||
int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2;
|
||||
if ((access & Opcodes.ACC_STATIC) != 0) {
|
||||
--size;
|
||||
}
|
||||
|
||||
maxLocals = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(int opcode, int var) {
|
||||
int n;
|
||||
if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD ||
|
||||
opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) {
|
||||
n = var + 2;
|
||||
}
|
||||
else {
|
||||
n = var + 1;
|
||||
}
|
||||
updateMaxLocals(n);
|
||||
|
||||
super.visitVarInsn(opcode, var);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIincInsn(int var, int increment) {
|
||||
updateMaxLocals(var + 1);
|
||||
|
||||
super.visitIincInsn(var, increment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(
|
||||
@NotNull String name, @NotNull String desc, String signature, @NotNull Label start, @NotNull Label end, int index
|
||||
) {
|
||||
// updates max locals
|
||||
char c = desc.charAt(0);
|
||||
int n = index + (c == 'J' || c == 'D' ? 2 : 1);
|
||||
updateMaxLocals(n);
|
||||
|
||||
super.visitLocalVariable(name, desc, signature, start, end, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(int maxStack, int maxLocals) {
|
||||
super.visitMaxs(maxStack, this.maxLocals);
|
||||
}
|
||||
|
||||
public int getMaxLocals() {
|
||||
return maxLocals;
|
||||
}
|
||||
|
||||
private void updateMaxLocals(int nextFreeSlotNumber) {
|
||||
if (nextFreeSlotNumber > maxLocals) {
|
||||
maxLocals = nextFreeSlotNumber;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,430 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.inline;
|
||||
|
||||
import com.intellij.openapi.util.Factory;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class MaxStackFrameSizeAndLocalsCalculator extends MaxLocalsCalculator {
|
||||
private static final int[] FRAME_SIZE_CHANGE_BY_OPCODE;
|
||||
static {
|
||||
// copy-pasted from org.jetbrains.org.objectweb.asm.Frame
|
||||
int i;
|
||||
int[] b = new int[202];
|
||||
String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD"
|
||||
+ "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD"
|
||||
+ "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED"
|
||||
+ "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE";
|
||||
for (i = 0; i < b.length; ++i) {
|
||||
b[i] = s.charAt(i) - 'E';
|
||||
}
|
||||
|
||||
FRAME_SIZE_CHANGE_BY_OPCODE = b;
|
||||
}
|
||||
|
||||
private final LabelWrapper firstLabel;
|
||||
|
||||
private LabelWrapper currentBlock;
|
||||
private LabelWrapper previousBlock;
|
||||
|
||||
/**
|
||||
* The (relative) stack size after the last visited instruction. This size
|
||||
* is relative to the beginning of the current basic block, i.e., the true
|
||||
* stack size after the last visited instruction is equal to the
|
||||
* {@link MaxStackFrameSizeAndLocalsCalculator.LabelWrapper#inputStackSize} of the current basic block
|
||||
* plus <tt>stackSize</tt>.
|
||||
*/
|
||||
private int stackSize;
|
||||
|
||||
/**
|
||||
* The (relative) maximum stack size after the last visited instruction.
|
||||
* This size is relative to the beginning of the current basic block, i.e.,
|
||||
* the true maximum stack size after the last visited instruction is equal
|
||||
* to the {@link MaxStackFrameSizeAndLocalsCalculator.LabelWrapper#inputStackSize} of the current basic
|
||||
* block plus <tt>stackSize</tt>.
|
||||
*/
|
||||
private int maxStackSize;
|
||||
|
||||
/**
|
||||
* Maximum stack size of this method.
|
||||
*/
|
||||
private int maxStack;
|
||||
|
||||
|
||||
private final Collection<ExceptionHandler> exceptionHandlers = new LinkedList<ExceptionHandler>();
|
||||
private final Map<Label, LabelWrapper> labelWrappersMap = new HashMap<Label, LabelWrapper>();
|
||||
|
||||
public MaxStackFrameSizeAndLocalsCalculator(int api, int access, String descriptor, MethodVisitor mv) {
|
||||
super(api, access, descriptor, mv);
|
||||
|
||||
firstLabel = getLabelWrapper(new Label());
|
||||
processLabel(firstLabel.label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
|
||||
throw new AssertionError("We don't support visitFrame because currently nobody needs");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInsn(int opcode) {
|
||||
increaseStackSize(FRAME_SIZE_CHANGE_BY_OPCODE[opcode]);
|
||||
|
||||
// if opcode == ATHROW or xRETURN, ends current block (no successor)
|
||||
if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) {
|
||||
noSuccessor();
|
||||
}
|
||||
|
||||
super.visitInsn(opcode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIntInsn(int opcode, int operand) {
|
||||
if (opcode != Opcodes.NEWARRAY) {
|
||||
// updates current and max stack sizes only if it's not NEWARRAY
|
||||
// (stack size variation is 0 for NEWARRAY and +1 BIPUSH or SIPUSH)
|
||||
increaseStackSize(1);
|
||||
}
|
||||
|
||||
super.visitIntInsn(opcode, operand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(int opcode, int var) {
|
||||
increaseStackSize(FRAME_SIZE_CHANGE_BY_OPCODE[opcode]);
|
||||
|
||||
super.visitVarInsn(opcode, var);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeInsn(int opcode, @NotNull String type) {
|
||||
if (opcode == Opcodes.NEW) {
|
||||
// updates current and max stack sizes only if opcode == NEW
|
||||
// (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF)
|
||||
increaseStackSize(1);
|
||||
}
|
||||
|
||||
super.visitTypeInsn(opcode, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(int opcode, @NotNull String owner, @NotNull String name, @NotNull String desc) {
|
||||
int stackSizeVariation;
|
||||
|
||||
// computes the stack size variation
|
||||
char c = desc.charAt(0);
|
||||
switch (opcode) {
|
||||
case Opcodes.GETSTATIC:
|
||||
stackSizeVariation = c == 'D' || c == 'J' ? 2 : 1;
|
||||
break;
|
||||
case Opcodes.PUTSTATIC:
|
||||
stackSizeVariation = c == 'D' || c == 'J' ? -2 : -1;
|
||||
break;
|
||||
case Opcodes.GETFIELD:
|
||||
stackSizeVariation = c == 'D' || c == 'J' ? 1 : 0;
|
||||
break;
|
||||
// case Constants.PUTFIELD:
|
||||
default:
|
||||
stackSizeVariation = c == 'D' || c == 'J' ? -3 : -2;
|
||||
break;
|
||||
}
|
||||
|
||||
increaseStackSize(stackSizeVariation);
|
||||
|
||||
super.visitFieldInsn(opcode, owner, name, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
|
||||
int argSize = Type.getArgumentsAndReturnSizes(desc);
|
||||
int sizeVariation;
|
||||
if (opcode == Opcodes.INVOKESTATIC) {
|
||||
sizeVariation = (argSize & 0x03) - (argSize >> 2) + 1;
|
||||
}
|
||||
else {
|
||||
sizeVariation = (argSize & 0x03) - (argSize >> 2);
|
||||
}
|
||||
|
||||
increaseStackSize(sizeVariation);
|
||||
|
||||
super.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(@NotNull String name, @NotNull String desc, @NotNull Handle bsm, @NotNull Object... bsmArgs) {
|
||||
int argSize = Type.getArgumentsAndReturnSizes(desc);
|
||||
increaseStackSize((argSize & 0x03) - (argSize >> 2) + 1);
|
||||
|
||||
super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJumpInsn(int opcode, @NotNull Label label) {
|
||||
if (currentBlock != null) {
|
||||
// updates current stack size (max stack size unchanged
|
||||
// because stack size variation always negative in this
|
||||
// case)
|
||||
stackSize += FRAME_SIZE_CHANGE_BY_OPCODE[opcode];
|
||||
addSuccessor(getLabelWrapper(label), stackSize);
|
||||
|
||||
if (opcode == Opcodes.GOTO) {
|
||||
noSuccessor();
|
||||
}
|
||||
}
|
||||
|
||||
super.visitJumpInsn(opcode, label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLabel(@NotNull Label label) {
|
||||
processLabel(label);
|
||||
super.visitLabel(label);
|
||||
}
|
||||
|
||||
private void processLabel(Label label) {
|
||||
LabelWrapper wrapper = getLabelWrapper(label);
|
||||
|
||||
if (currentBlock != null) {
|
||||
// ends current block (with one new successor)
|
||||
currentBlock.outputStackMax = maxStackSize;
|
||||
addSuccessor(wrapper, stackSize);
|
||||
}
|
||||
|
||||
// begins a new current block
|
||||
currentBlock = wrapper;
|
||||
// resets the relative current and max stack sizes
|
||||
stackSize = 0;
|
||||
maxStackSize = 0;
|
||||
|
||||
if (previousBlock != null) {
|
||||
previousBlock.nextLabel = wrapper;
|
||||
}
|
||||
|
||||
previousBlock = wrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(@NotNull Object cst) {
|
||||
// computes the stack size variation
|
||||
if (cst instanceof Long || cst instanceof Double) {
|
||||
increaseStackSize(2);
|
||||
}
|
||||
else {
|
||||
increaseStackSize(1);
|
||||
}
|
||||
|
||||
super.visitLdcInsn(cst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableSwitchInsn(int min, int max, @NotNull Label dflt, @NotNull Label... labels) {
|
||||
visitSwitchInsn(dflt, labels);
|
||||
|
||||
super.visitTableSwitchInsn(min, max, dflt, labels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLookupSwitchInsn(@NotNull Label dflt, @NotNull int[] keys, @NotNull Label[] labels) {
|
||||
visitSwitchInsn(dflt, labels);
|
||||
|
||||
super.visitLookupSwitchInsn(dflt, keys, labels);
|
||||
}
|
||||
|
||||
private void visitSwitchInsn(Label dflt, Label[] labels) {
|
||||
if (currentBlock != null) {
|
||||
// updates current stack size (max stack size unchanged)
|
||||
--stackSize;
|
||||
// adds current block successors
|
||||
addSuccessor(getLabelWrapper(dflt), stackSize);
|
||||
for (Label label : labels) {
|
||||
addSuccessor(getLabelWrapper(label), stackSize);
|
||||
}
|
||||
// ends current block
|
||||
noSuccessor();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMultiANewArrayInsn(@NotNull String desc, int dims) {
|
||||
if (currentBlock != null) {
|
||||
increaseStackSize(dims - 1);
|
||||
}
|
||||
|
||||
super.visitMultiANewArrayInsn(desc, dims);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(int maxStack, int maxLocals) {
|
||||
// completes the control flow graph with exception handler blocks
|
||||
for (ExceptionHandler handler : exceptionHandlers) {
|
||||
LabelWrapper l = handler.start;
|
||||
LabelWrapper e = handler.end;
|
||||
|
||||
while (l != e) {
|
||||
l.addSuccessor(handler.handlerLabel, 0, true);
|
||||
l = l.nextLabel;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* control flow analysis algorithm: while the block stack is not
|
||||
* empty, pop a block from this stack, update the max stack size,
|
||||
* compute the true (non relative) begin stack size of the
|
||||
* successors of this block, and push these successors onto the
|
||||
* stack (unless they have already been pushed onto the stack).
|
||||
* Note: by hypothesis, the {@link LabelWrapper#inputStackSize} of the
|
||||
* blocks in the block stack are the true (non relative) beginning
|
||||
* stack sizes of these blocks.
|
||||
*/
|
||||
int max = 0;
|
||||
Stack<LabelWrapper> stack = new Stack<LabelWrapper>();
|
||||
Set<LabelWrapper> pushed = new HashSet<LabelWrapper>();
|
||||
|
||||
stack.push(firstLabel);
|
||||
pushed.add(firstLabel);
|
||||
|
||||
while (!stack.empty()) {
|
||||
LabelWrapper current = stack.pop();
|
||||
int start = current.inputStackSize;
|
||||
int blockMax = start + current.outputStackMax;
|
||||
|
||||
// updates the global max stack size
|
||||
if (blockMax > max) {
|
||||
max = blockMax;
|
||||
}
|
||||
|
||||
// analyzes the successors of the block
|
||||
for (ControlFlowEdge edge : current.successors) {
|
||||
LabelWrapper successor = edge.successor;
|
||||
|
||||
if (!pushed.contains(successor)) {
|
||||
// computes its true beginning stack size...
|
||||
successor.inputStackSize = edge.isExceptional ? 1 : start + edge.outputStackSize;
|
||||
// ...and pushes it onto the stack
|
||||
pushed.add(successor);
|
||||
stack.push(successor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.maxStack = Math.max(this.maxStack, Math.max(maxStack, max));
|
||||
|
||||
super.visitMaxs(this.maxStack, maxLocals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTryCatchBlock(
|
||||
@NotNull Label start, @NotNull Label end,
|
||||
@NotNull Label handler, String type
|
||||
) {
|
||||
ExceptionHandler exceptionHandler = new ExceptionHandler(
|
||||
getLabelWrapper(start), getLabelWrapper(end), getLabelWrapper(handler)
|
||||
);
|
||||
|
||||
exceptionHandlers.add(exceptionHandler);
|
||||
|
||||
super.visitTryCatchBlock(start, end, handler, type);
|
||||
}
|
||||
|
||||
private static class ExceptionHandler {
|
||||
private final LabelWrapper start;
|
||||
private final LabelWrapper end;
|
||||
private final LabelWrapper handlerLabel;
|
||||
|
||||
public ExceptionHandler(
|
||||
LabelWrapper start,
|
||||
LabelWrapper end,
|
||||
LabelWrapper handlerLabel
|
||||
) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.handlerLabel = handlerLabel;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ControlFlowEdge {
|
||||
private final LabelWrapper successor;
|
||||
private final int outputStackSize;
|
||||
private final boolean isExceptional;
|
||||
|
||||
public ControlFlowEdge(LabelWrapper successor, int outputStackSize, boolean isExceptional) {
|
||||
this.successor = successor;
|
||||
this.outputStackSize = outputStackSize;
|
||||
this.isExceptional = isExceptional;
|
||||
}
|
||||
}
|
||||
|
||||
private static class LabelWrapper {
|
||||
private final Label label;
|
||||
private LabelWrapper nextLabel = null;
|
||||
private final Collection<ControlFlowEdge> successors = new LinkedList<ControlFlowEdge>();
|
||||
|
||||
private int outputStackMax = 0;
|
||||
private int inputStackSize = 0;
|
||||
public LabelWrapper(Label label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
private void addSuccessor(LabelWrapper successor, int outputStackSize, boolean isExceptional) {
|
||||
successors.add(new ControlFlowEdge(successor, outputStackSize, isExceptional));
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Utility methods
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
private LabelWrapper getLabelWrapper(final Label label) {
|
||||
return ContainerUtil.getOrCreate(labelWrappersMap, label, new Factory<LabelWrapper>() {
|
||||
@Override
|
||||
public LabelWrapper create() {
|
||||
return new LabelWrapper(label);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void increaseStackSize(int variation) {
|
||||
updateStackSize(stackSize + variation);
|
||||
}
|
||||
|
||||
private void updateStackSize(int size) {
|
||||
if (size > maxStackSize) {
|
||||
maxStackSize = size;
|
||||
}
|
||||
|
||||
stackSize = size;
|
||||
}
|
||||
|
||||
private void addSuccessor(LabelWrapper successor, int outputStackSize) {
|
||||
currentBlock.addSuccessor(successor, outputStackSize, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the current basic block. This method must be used in the case where
|
||||
* the current basic block does not have any successor.
|
||||
*/
|
||||
private void noSuccessor() {
|
||||
if (currentBlock != null) {
|
||||
currentBlock.outputStackMax = maxStackSize;
|
||||
currentBlock = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,17 @@
|
||||
package org.jetbrains.jet.codegen.inline;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.codegen.ClosureCodegen;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
|
||||
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
|
||||
import org.jetbrains.jet.lang.resolve.kotlin.KotlinBinaryClassCache;
|
||||
import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
@@ -34,9 +40,7 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.codegen.inline.InlineCodegenUtil.getReturnType;
|
||||
import static org.jetbrains.jet.codegen.inline.InlineCodegenUtil.isAnonymousConstructorCall;
|
||||
import static org.jetbrains.jet.codegen.inline.InlineCodegenUtil.isInvokeOnLambda;
|
||||
import static org.jetbrains.jet.codegen.inline.InlineCodegenUtil.*;
|
||||
|
||||
public class MethodInliner {
|
||||
|
||||
@@ -63,6 +67,8 @@ public class MethodInliner {
|
||||
|
||||
private final InlineResult result;
|
||||
|
||||
private int lambdasFinallyBlocks;
|
||||
|
||||
/*
|
||||
*
|
||||
* @param node
|
||||
@@ -115,8 +121,12 @@ public class MethodInliner {
|
||||
}
|
||||
|
||||
resultNode.visitLabel(end);
|
||||
processReturns(resultNode, labelOwner, remapReturn, end);
|
||||
|
||||
if (inliningContext.isRoot()) {
|
||||
InternalFinallyBlockInliner.processInlineFunFinallyBlocks(resultNode, lambdasFinallyBlocks);
|
||||
}
|
||||
|
||||
processReturns(resultNode, labelOwner, remapReturn, end);
|
||||
//flush transformed node to output
|
||||
resultNode.accept(new InliningInstructionAdapter(adapter));
|
||||
|
||||
@@ -127,7 +137,7 @@ public class MethodInliner {
|
||||
|
||||
final Deque<InvokeCall> currentInvokes = new LinkedList<InvokeCall>(invokeCalls);
|
||||
|
||||
MethodNode resultNode = new MethodNode(node.access, node.name, node.desc, node.signature, null);
|
||||
final MethodNode resultNode = new MethodNode(node.access, node.name, node.desc, node.signature, null);
|
||||
|
||||
final Iterator<ConstructorInvocation> iterator = constructorInvocations.iterator();
|
||||
|
||||
@@ -186,6 +196,7 @@ public class MethodInliner {
|
||||
int valueParamShift = getNextLocalIndex();//NB: don't inline cause it changes
|
||||
putStackValuesIntoLocals(info.getInvokeParamsWithoutCaptured(), valueParamShift, this, desc);
|
||||
|
||||
addInlineMarker(this, true);
|
||||
Parameters lambdaParameters = info.addAllParameters(nodeRemapper);
|
||||
|
||||
InlinedLambdaRemapper newCapturedRemapper =
|
||||
@@ -207,6 +218,7 @@ public class MethodInliner {
|
||||
Method delegate = typeMapper.mapSignature(info.getFunctionDescriptor()).getAsmMethod();
|
||||
StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), this);
|
||||
setLambdaInlining(false);
|
||||
addInlineMarker(this, false);
|
||||
}
|
||||
else if (isAnonymousConstructorCall(owner, name)) { //TODO add method
|
||||
assert invocation != null : "<init> call not corresponds to new call" + owner + " " + name;
|
||||
@@ -227,6 +239,12 @@ public class MethodInliner {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(int stack, int locals) {
|
||||
lambdasFinallyBlocks = resultNode.tryCatchBlocks.size();
|
||||
super.visitMaxs(stack, locals);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
node.accept(lambdaInliner);
|
||||
@@ -338,7 +356,7 @@ public class MethodInliner {
|
||||
|
||||
AbstractInsnNode cur = node.instructions.getFirst();
|
||||
int index = 0;
|
||||
Set<LabelNode> deadLabels = new HashSet<LabelNode>();
|
||||
Set<LabelNode> possibleDeadLabels = new HashSet<LabelNode>();
|
||||
|
||||
while (cur != null) {
|
||||
Frame<SourceValue> frame = sources[index];
|
||||
@@ -398,10 +416,15 @@ public class MethodInliner {
|
||||
if (frame == null) {
|
||||
//clean dead code otherwise there is problems in unreachable finally block, don't touch label it cause try/catch/finally problems
|
||||
if (prevNode.getType() == AbstractInsnNode.LABEL) {
|
||||
deadLabels.add((LabelNode) prevNode);
|
||||
possibleDeadLabels.add((LabelNode) prevNode);
|
||||
} else {
|
||||
node.instructions.remove(prevNode);
|
||||
}
|
||||
} else {
|
||||
//Cause we generate exception table for default handler using gaps (see ExpressionCodegen.visitTryExpression)
|
||||
//it may occurs that interval for default handler starts before catch start label, so this label seems as dead,
|
||||
//but as result all this labels will be merged into one (see KT-5863)
|
||||
possibleDeadLabels.remove(prevNode.getPrevious());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,7 +432,7 @@ public class MethodInliner {
|
||||
List<TryCatchBlockNode> blocks = node.tryCatchBlocks;
|
||||
for (Iterator<TryCatchBlockNode> iterator = blocks.iterator(); iterator.hasNext(); ) {
|
||||
TryCatchBlockNode block = iterator.next();
|
||||
if (deadLabels.contains(block.start) && deadLabels.contains(block.end)) {
|
||||
if (possibleDeadLabels.contains(block.start) && possibleDeadLabels.contains(block.end)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
@@ -523,7 +546,6 @@ public class MethodInliner {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: check annotation on class - it's package part
|
||||
//TODO: check it's external module
|
||||
//TODO?: assert method exists in facade?
|
||||
public String changeOwnerForExternalPackage(String type, int opcode) {
|
||||
@@ -531,10 +553,18 @@ public class MethodInliner {
|
||||
return type;
|
||||
}
|
||||
|
||||
int i = type.indexOf('-');
|
||||
if (i >= 0) {
|
||||
return type.substring(0, i);
|
||||
JvmClassName name = JvmClassName.byInternalName(type);
|
||||
String packageClassInternalName = PackageClassUtils.getPackageClassInternalName(name.getPackageFqName());
|
||||
if (type.startsWith(packageClassInternalName + '$')) {
|
||||
VirtualFile virtualFile = InlineCodegenUtil.findVirtualFile(inliningContext.state.getProject(), type);
|
||||
if (virtualFile != null) {
|
||||
KotlinJvmBinaryClass klass = KotlinBinaryClassCache.getKotlinBinaryClass(virtualFile);
|
||||
if (klass != null && klass.getClassHeader().getSyntheticClassKind() == KotlinSyntheticClass.Kind.PACKAGE_PART) {
|
||||
return packageClassInternalName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -542,18 +572,20 @@ public class MethodInliner {
|
||||
public RuntimeException wrapException(@NotNull Exception originalException, @NotNull MethodNode node, @NotNull String errorSuffix) {
|
||||
if (originalException instanceof InlineException) {
|
||||
return new InlineException(errorPrefix + ": " + errorSuffix, originalException);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return new InlineException(errorPrefix + ": " + errorSuffix + "\ncause: " +
|
||||
InlineCodegen.getNodeText(node), originalException);
|
||||
getNodeText(node), originalException);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<FinallyBlockInfo> processReturns(@NotNull MethodNode node, @NotNull LabelOwner labelOwner, boolean remapReturn, Label endLabel) {
|
||||
//process local and global returns (local substituted with goto end-label global kept unchanged)
|
||||
public static List<ExternalFinallyBlockInfo> processReturns(@NotNull MethodNode node, @NotNull LabelOwner labelOwner, boolean remapReturn, Label endLabel) {
|
||||
if (!remapReturn) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<FinallyBlockInfo> result = new ArrayList<FinallyBlockInfo>();
|
||||
List<ExternalFinallyBlockInfo> result = new ArrayList<ExternalFinallyBlockInfo>();
|
||||
InsnList instructions = node.instructions;
|
||||
AbstractInsnNode insnNode = instructions.getFirst();
|
||||
while (insnNode != null) {
|
||||
@@ -584,23 +616,25 @@ public class MethodInliner {
|
||||
}
|
||||
|
||||
//genetate finally block before nonLocalReturn flag/return/goto
|
||||
result.add(new FinallyBlockInfo(isLocalReturn ? insnNode : insnNode.getPrevious(), getReturnType(insnNode.getOpcode())));
|
||||
result.add(new ExternalFinallyBlockInfo(isLocalReturn ? insnNode : insnNode.getPrevious(), getReturnType(insnNode.getOpcode())
|
||||
));
|
||||
}
|
||||
insnNode = insnNode.getNext();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static class FinallyBlockInfo {
|
||||
public static class ExternalFinallyBlockInfo {
|
||||
|
||||
final AbstractInsnNode beforeIns;
|
||||
|
||||
final Type returnType;
|
||||
|
||||
public FinallyBlockInfo(AbstractInsnNode beforeIns, Type returnType) {
|
||||
public ExternalFinallyBlockInfo(AbstractInsnNode beforeIns, Type returnType) {
|
||||
this.beforeIns = beforeIns;
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.inline
|
||||
|
||||
import java.util.ArrayList
|
||||
import org.jetbrains.org.objectweb.asm.tree.TryCatchBlockNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.LabelNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.jet.codegen.inline.InlineCodegenUtil.*
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
enum class TryCatchPosition {
|
||||
START
|
||||
END
|
||||
INNER
|
||||
}
|
||||
|
||||
trait IntervalWithHandler {
|
||||
val startLabel: LabelNode
|
||||
val endLabel: LabelNode
|
||||
val handler: LabelNode
|
||||
val `type`: String?
|
||||
}
|
||||
|
||||
class TryCatchBlockNodeInfo(val node: TryCatchBlockNode, val onlyCopyNotProcess: Boolean) : IntervalWithHandler {
|
||||
|
||||
override val startLabel: LabelNode
|
||||
get() = node.start
|
||||
override val endLabel: LabelNode
|
||||
get() = node.end
|
||||
override val handler: LabelNode
|
||||
get() = node.handler!!
|
||||
override val `type`: String?
|
||||
get() = node.`type`
|
||||
}
|
||||
|
||||
class TryCatchBlockNodePosition(val nodeInfo: TryCatchBlockNodeInfo, var position: TryCatchPosition): IntervalWithHandler by nodeInfo
|
||||
|
||||
class TryBlockCluster<T : IntervalWithHandler>(val blocks: MutableList<T>) {
|
||||
val defaultHandler: T?
|
||||
get() = blocks.firstOrNull() { it.`type` == null }
|
||||
}
|
||||
|
||||
|
||||
fun <T: IntervalWithHandler> doClustering(blocks: List<T>) : List<TryBlockCluster<T>> {
|
||||
[data] class TryBlockInterval(val startLabel: LabelNode, val endLabel: LabelNode)
|
||||
|
||||
val clusters = linkedMapOf<TryBlockInterval, TryBlockCluster<T>>()
|
||||
blocks.forEach { block ->
|
||||
val interval = TryBlockInterval(firstLabelInChain(block.startLabel), firstLabelInChain(block.endLabel))
|
||||
val cluster = clusters.getOrPut(interval, {TryBlockCluster(arrayListOf())})
|
||||
cluster.blocks.add(block)
|
||||
}
|
||||
|
||||
return clusters.values().toList();
|
||||
}
|
||||
|
||||
@@ -33,10 +33,11 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class OptimizationMethodVisitor extends MethodVisitor {
|
||||
private static final int MAX_INSTRUCTIONS_SIZE_TO_OPTIMIZE = 5000;
|
||||
private static final MethodTransformer MAIN_METHOD_TRANSFORMER = new RedundantNullCheckMethodTransformer(
|
||||
new RedundantBoxingMethodTransformer(null)
|
||||
);
|
||||
private static final int MEMORY_LIMIT_BY_METHOD_MB = 50;
|
||||
private static final MethodTransformer[] TRANSFORMERS = new MethodTransformer[]{
|
||||
new RedundantNullCheckMethodTransformer(), new RedundantBoxingMethodTransformer(),
|
||||
new RedundantGotoMethodTransformer(), new StoreStackBeforeInlineMethodTransformer()
|
||||
};
|
||||
|
||||
private final MethodNode methodNode;
|
||||
private final MethodVisitor delegate;
|
||||
@@ -65,9 +66,10 @@ public class OptimizationMethodVisitor extends MethodVisitor {
|
||||
|
||||
super.visitEnd();
|
||||
|
||||
if (methodNode.instructions.size() > 0 &&
|
||||
methodNode.instructions.size() <= MAX_INSTRUCTIONS_SIZE_TO_OPTIMIZE) {
|
||||
MAIN_METHOD_TRANSFORMER.transform("fake", methodNode);
|
||||
if (canBeAnalyzed(methodNode)) {
|
||||
for (MethodTransformer transformer : TRANSFORMERS) {
|
||||
transformer.transform("fake", methodNode);
|
||||
}
|
||||
}
|
||||
|
||||
methodNode.accept(new EndIgnoringMethodVisitorDecorator(Opcodes.ASM5, delegate));
|
||||
@@ -113,4 +115,12 @@ public class OptimizationMethodVisitor extends MethodVisitor {
|
||||
|
||||
return traceMethodVisitor;
|
||||
}
|
||||
|
||||
private static boolean canBeAnalyzed(@NotNull MethodNode node) {
|
||||
int totalFramesSizeMb = node.instructions.size() *
|
||||
(node.maxLocals + node.maxStack) / (1024 * 1024);
|
||||
|
||||
return node.instructions.size() > 0 &&
|
||||
totalFramesSizeMb < MEMORY_LIMIT_BY_METHOD_MB;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.optimization
|
||||
|
||||
import org.jetbrains.jet.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.LabelNode
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode
|
||||
|
||||
|
||||
public class RedundantGotoMethodTransformer : MethodTransformer() {
|
||||
/**
|
||||
* Removes redundant GOTO's, i.e. to subsequent labels
|
||||
*/
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
val insns = methodNode.instructions.toArray()
|
||||
val insnsToRemove = arrayListOf<AbstractInsnNode>()
|
||||
|
||||
val currentLabels = hashSetOf<LabelNode>()
|
||||
for (insn in insns.reverse()) {
|
||||
if (insn.isMeaningful) {
|
||||
if (insn.getOpcode() == Opcodes.GOTO && (insn as JumpInsnNode).label in currentLabels) {
|
||||
insnsToRemove.add(insn)
|
||||
}
|
||||
else {
|
||||
currentLabels.clear()
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if (insn is LabelNode) {
|
||||
currentLabels.add(insn)
|
||||
}
|
||||
}
|
||||
|
||||
for (insnToRemove in insnsToRemove) {
|
||||
methodNode.instructions.remove(insnToRemove)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val AbstractInsnNode.isMeaningful : Boolean get() =
|
||||
when (this.getType()) {
|
||||
AbstractInsnNode.LABEL, AbstractInsnNode.LINE, AbstractInsnNode.FRAME -> false
|
||||
else -> true
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.codegen.optimization
|
||||
|
||||
import org.jetbrains.jet.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.jet.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.jet.codegen.inline.InlineCodegenUtil
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import org.jetbrains.org.objectweb.asm.tree.VarInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import com.intellij.util.containers.Stack
|
||||
|
||||
class StoreStackBeforeInlineMethodTransformer : MethodTransformer() {
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
val frames = MethodTransformer.analyze(internalClassName, methodNode, OptimizationBasicInterpreter())
|
||||
if (needToProcess(methodNode, frames)) {
|
||||
process(methodNode, frames)
|
||||
}
|
||||
else {
|
||||
removeInlineMarkers(methodNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun needToProcess(node: MethodNode, frames: Array<Frame<BasicValue>?>): Boolean {
|
||||
val insns = node.instructions.toArray()
|
||||
var balance = 0
|
||||
var isThereAnyInlineMarker = false
|
||||
|
||||
for ((insn, frame) in insns.zip(frames)) {
|
||||
if (isInlineMarker(insn)) {
|
||||
isThereAnyInlineMarker = true
|
||||
|
||||
// inline marker is not available
|
||||
if (frame == null) return false
|
||||
}
|
||||
|
||||
if (isBeforeInlineMarker(insn)) {
|
||||
balance++
|
||||
}
|
||||
else if(isAfterInlineMarker(insn)) {
|
||||
balance--
|
||||
}
|
||||
|
||||
if (balance < 0) return false
|
||||
}
|
||||
|
||||
return balance == 0 && isThereAnyInlineMarker
|
||||
}
|
||||
|
||||
private fun isBeforeInlineMarker(insn: AbstractInsnNode) = isInlineMarker(insn, InlineCodegenUtil.INLINE_MARKER_BEFORE_METHOD_NAME)
|
||||
|
||||
private fun isAfterInlineMarker(insn: AbstractInsnNode) = isInlineMarker(insn, InlineCodegenUtil.INLINE_MARKER_AFTER_METHOD_NAME)
|
||||
|
||||
private fun isInlineMarker(insn: AbstractInsnNode, markerName: String? = null): Boolean {
|
||||
return insn.getOpcode() == Opcodes.INVOKESTATIC &&
|
||||
insn is MethodInsnNode &&
|
||||
insn.owner == InlineCodegenUtil.INLINE_MARKER_CLASS_NAME &&
|
||||
if (markerName != null) markerName == insn.name else true
|
||||
}
|
||||
|
||||
private fun process(methodNode: MethodNode, frames: Array<Frame<BasicValue>?>) {
|
||||
val insns = methodNode.instructions.toArray()
|
||||
|
||||
val storedValuesDescriptorsStack = Stack<StoredStackValuesDescriptor>()
|
||||
var firstAvailableVarIndex = methodNode.maxLocals
|
||||
var currentStoredValuesCount = 0
|
||||
|
||||
for ((insn, frame) in insns.zip(frames)) {
|
||||
if (isBeforeInlineMarker(insn)) {
|
||||
frame ?: throw AssertionError("process method shouldn't be called if frame is null before inline marker")
|
||||
|
||||
val desc = storeStackValues(methodNode, frame, insn, firstAvailableVarIndex, currentStoredValuesCount)
|
||||
|
||||
firstAvailableVarIndex += desc.storedStackSize
|
||||
currentStoredValuesCount += desc.storedValuesCount
|
||||
storedValuesDescriptorsStack.push(desc)
|
||||
}
|
||||
else if (isAfterInlineMarker(insn)) {
|
||||
frame ?: throw AssertionError("process method shouldn't be called if frame is null before inline marker")
|
||||
|
||||
val desc = storedValuesDescriptorsStack.pop() ?:
|
||||
throw AssertionError("should be non null becase markers are balanced")
|
||||
|
||||
loadStackValues(methodNode, frame, insn, desc)
|
||||
firstAvailableVarIndex -= desc.storedStackSize
|
||||
currentStoredValuesCount -= desc.storedValuesCount
|
||||
}
|
||||
|
||||
if (isInlineMarker(insn)) {
|
||||
methodNode.instructions.remove(insn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class StoredStackValuesDescriptor(
|
||||
val values: List<BasicValue>,
|
||||
val firstVariableIndex: Int,
|
||||
val storedStackSize: Int,
|
||||
alreadyStoredValuesCount: Int
|
||||
) {
|
||||
val nextFreeVarIndex : Int get() = firstVariableIndex + storedStackSize
|
||||
val storedValuesCount: Int get() = values.size
|
||||
val isStored: Boolean get() = storedValuesCount > 0
|
||||
val totalValuesCountOnStackBeforeInline = alreadyStoredValuesCount + storedValuesCount
|
||||
}
|
||||
|
||||
private fun removeInlineMarkers(node: MethodNode) {
|
||||
for (insn in node.instructions.toArray()) {
|
||||
if (isInlineMarker(insn)) {
|
||||
node.instructions.remove(insn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun storeStackValues(
|
||||
node: MethodNode,
|
||||
frame: Frame<BasicValue>,
|
||||
beforeInlineMarker: AbstractInsnNode,
|
||||
firstAvailableVarIndex: Int,
|
||||
alreadyStoredValuesCount: Int
|
||||
) : StoredStackValuesDescriptor {
|
||||
var stackSize = 0
|
||||
|
||||
val values = frame.getStackValuesStartingFrom(alreadyStoredValuesCount)
|
||||
|
||||
for (value in values.reverse()) {
|
||||
node.instructions.insertBefore(
|
||||
beforeInlineMarker,
|
||||
VarInsnNode(
|
||||
value.getType()!!.getOpcode(Opcodes.ISTORE),
|
||||
firstAvailableVarIndex + stackSize
|
||||
)
|
||||
)
|
||||
stackSize += value.getSize()
|
||||
}
|
||||
|
||||
node.updateMaxLocals(firstAvailableVarIndex + stackSize)
|
||||
|
||||
return StoredStackValuesDescriptor(values, firstAvailableVarIndex, stackSize, alreadyStoredValuesCount)
|
||||
}
|
||||
|
||||
private fun loadStackValues(
|
||||
node: MethodNode,
|
||||
frame: Frame<BasicValue>,
|
||||
afterInlineMarker: AbstractInsnNode,
|
||||
desc: StoredStackValuesDescriptor
|
||||
) {
|
||||
if (!desc.isStored) return
|
||||
|
||||
val insns = node.instructions
|
||||
var returnValueVarIndex = -1
|
||||
var returnType : Type? = null
|
||||
|
||||
if (frame.getStackSize() != desc.totalValuesCountOnStackBeforeInline) {
|
||||
// only returned value
|
||||
assert(
|
||||
(frame.getStackSize() - desc.totalValuesCountOnStackBeforeInline) == 1,
|
||||
"Stack sizes should not differ by more than 1 (returned value)"
|
||||
)
|
||||
|
||||
returnValueVarIndex = desc.nextFreeVarIndex
|
||||
returnType = frame.getStack(frame.getStackSize() - 1)!!.getType()
|
||||
node.updateMaxLocals(returnValueVarIndex + returnType!!.getSize())
|
||||
|
||||
insns.insertBefore(
|
||||
afterInlineMarker,
|
||||
VarInsnNode(returnType!!.getOpcode(Opcodes.ISTORE), returnValueVarIndex)
|
||||
)
|
||||
}
|
||||
|
||||
var currentVarIndex = desc.firstVariableIndex + desc.storedStackSize
|
||||
|
||||
for (value in desc.values) {
|
||||
currentVarIndex -= value.getSize()
|
||||
insns.insertBefore(
|
||||
afterInlineMarker,
|
||||
VarInsnNode(
|
||||
value.getType()!!.getOpcode(Opcodes.ILOAD),
|
||||
currentVarIndex
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (returnValueVarIndex != -1) {
|
||||
insns.insertBefore(
|
||||
afterInlineMarker,
|
||||
VarInsnNode(returnType!!.getOpcode(Opcodes.ILOAD), returnValueVarIndex)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <V : BasicValue> Frame<V>.getStackValuesStartingFrom(from: Int): List<V> =
|
||||
IntRange(from, getStackSize() - 1).map { getStack(it) }.requireNoNulls()
|
||||
|
||||
private fun MethodNode.updateMaxLocals(newMaxLocals: Int) {
|
||||
maxLocals = Math.max(maxLocals, newMaxLocals)
|
||||
}
|
||||
@@ -211,22 +211,12 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter {
|
||||
return v;
|
||||
}
|
||||
|
||||
if (v instanceof BoxedBasicValue && w == BasicValue.UNINITIALIZED_VALUE) {
|
||||
return v;
|
||||
}
|
||||
|
||||
if (w instanceof BoxedBasicValue && v == BasicValue.UNINITIALIZED_VALUE) {
|
||||
return w;
|
||||
}
|
||||
|
||||
if (v instanceof BoxedBasicValue) {
|
||||
onMergeFail((BoxedBasicValue) v);
|
||||
return MIXED_VALUE;
|
||||
}
|
||||
|
||||
if (w instanceof BoxedBasicValue) {
|
||||
onMergeFail((BoxedBasicValue) w);
|
||||
return MIXED_VALUE;
|
||||
}
|
||||
|
||||
return super.merge(v, w);
|
||||
|
||||
@@ -31,9 +31,6 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Frame;
|
||||
import java.util.*;
|
||||
|
||||
public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
public RedundantBoxingMethodTransformer(MethodTransformer methodTransformer) {
|
||||
super(methodTransformer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(@NotNull String internalClassName, @NotNull MethodNode node) {
|
||||
@@ -55,8 +52,6 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
|
||||
adaptInstructionsForBoxedValues(node, valuesToOptimize);
|
||||
}
|
||||
|
||||
super.transform(internalClassName, node);
|
||||
}
|
||||
|
||||
private static void interpretPopInstructionsForBoxedValues(
|
||||
|
||||
@@ -28,18 +28,12 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class RedundantNullCheckMethodTransformer extends MethodTransformer {
|
||||
public RedundantNullCheckMethodTransformer(MethodTransformer methodTransformer) {
|
||||
super(methodTransformer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(@NotNull String internalClassName, @NotNull MethodNode methodNode) {
|
||||
|
||||
while (removeRedundantNullCheckPass(internalClassName, methodNode)) {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
super.transform(internalClassName, methodNode);
|
||||
}
|
||||
|
||||
private static boolean removeRedundantNullCheckPass(@NotNull String internalClassName, @NotNull MethodNode methodNode) {
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.BasicInterpreter;
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue;
|
||||
|
||||
public class OptimizationBasicInterpreter extends BasicInterpreter {
|
||||
public static final BasicValue MIXED_VALUE = new BasicValue(Type.getObjectType("#"));
|
||||
private static final BasicValue BOOLEAN_VALUE = new BasicValue(Type.BOOLEAN_TYPE);
|
||||
private static final BasicValue CHAR_VALUE = new BasicValue(Type.CHAR_TYPE);
|
||||
private static final BasicValue BYTE_VALUE = new BasicValue(Type.BYTE_TYPE);
|
||||
@@ -93,7 +92,25 @@ public class OptimizationBasicInterpreter extends BasicInterpreter {
|
||||
@NotNull BasicValue v, @NotNull BasicValue w
|
||||
) {
|
||||
if (!v.equals(w)) {
|
||||
return MIXED_VALUE;
|
||||
if (v == BasicValue.UNINITIALIZED_VALUE || w == BasicValue.UNINITIALIZED_VALUE) {
|
||||
return BasicValue.UNINITIALIZED_VALUE;
|
||||
}
|
||||
|
||||
// if merge of two references then `lub` is java/lang/Object
|
||||
// arrays also are BasicValues with reference type's
|
||||
if (v.getType().getSort() == Type.OBJECT && w.getType().getSort() == Type.OBJECT) {
|
||||
return BasicValue.REFERENCE_VALUE;
|
||||
}
|
||||
|
||||
assert v.getType().getSort() != Type.ARRAY && w.getType().getSort() != Type.ARRAY : "There should not be arrays";
|
||||
|
||||
// if merge of something can be stored in int var (int, char, boolean, byte, character)
|
||||
if (v.getType().getOpcode(Opcodes.ISTORE) == Opcodes.ISTORE &&
|
||||
w.getType().getOpcode(Opcodes.ISTORE) == Opcodes.ISTORE) {
|
||||
return BasicValue.INT_VALUE;
|
||||
}
|
||||
|
||||
return BasicValue.UNINITIALIZED_VALUE;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -16,17 +16,15 @@
|
||||
|
||||
package org.jetbrains.jet.codegen.optimization.transformer;
|
||||
|
||||
import kotlin.jvm.KotlinSignature;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.*;
|
||||
|
||||
public abstract class MethodTransformer {
|
||||
private final MethodTransformer delegate;
|
||||
|
||||
protected MethodTransformer(MethodTransformer delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@KotlinSignature("fun <V : Value?> runAnalyzer(analyzer: Analyzer<V>, internalClassName: String, node: MethodNode): Array<Frame<V>?>")
|
||||
@NotNull
|
||||
protected static <V extends Value> Frame<V>[] runAnalyzer(
|
||||
@NotNull Analyzer<V> analyzer,
|
||||
@NotNull String internalClassName,
|
||||
@@ -39,6 +37,9 @@ public abstract class MethodTransformer {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@KotlinSignature("fun <V : Value?> analyze(internalClassName: String, node: MethodNode, interpreter: Interpreter<V>): Array<Frame<V>?>")
|
||||
@NotNull
|
||||
protected static <V extends Value> Frame<V>[] analyze(
|
||||
@NotNull String internalClassName,
|
||||
@NotNull MethodNode node,
|
||||
@@ -47,9 +48,5 @@ public abstract class MethodTransformer {
|
||||
return runAnalyzer(new Analyzer<V>(interpreter), internalClassName, node);
|
||||
}
|
||||
|
||||
public void transform(@NotNull String internalClassName, @NotNull MethodNode methodNode) {
|
||||
if (delegate != null) {
|
||||
delegate.transform(internalClassName, methodNode);
|
||||
}
|
||||
}
|
||||
abstract public void transform(@NotNull String internalClassName, @NotNull MethodNode methodNode);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.codegen.*;
|
||||
import org.jetbrains.jet.codegen.binding.CalculatedClosure;
|
||||
import org.jetbrains.jet.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.jet.codegen.binding.PsiCodegenPredictor;
|
||||
import org.jetbrains.jet.codegen.context.CodegenContext;
|
||||
import org.jetbrains.jet.codegen.signature.BothSignatureWriter;
|
||||
import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedCallableMemberDescriptor;
|
||||
@@ -48,6 +49,7 @@ import org.jetbrains.jet.lang.resolve.java.mapping.KotlinToJavaTypesMap;
|
||||
import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
|
||||
import org.jetbrains.jet.lang.resolve.name.SpecialNames;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
@@ -277,7 +279,7 @@ public class JetTypeMapper {
|
||||
}
|
||||
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
Type asmType = getAsmType(bindingContext, (ClassDescriptor) descriptor);
|
||||
Type asmType = computeAsmType((ClassDescriptor) descriptor.getOriginal());
|
||||
writeGenericType(signatureVisitor, asmType, jetType, howThisTypeIsUsed, projectionsAllowed);
|
||||
return asmType;
|
||||
}
|
||||
@@ -294,9 +296,48 @@ public class JetTypeMapper {
|
||||
throw new UnsupportedOperationException("Unknown type " + jetType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Type computeAsmType(@NotNull ClassDescriptor klass) {
|
||||
Type alreadyComputedType = bindingContext.get(ASM_TYPE, klass);
|
||||
if (alreadyComputedType != null) {
|
||||
return alreadyComputedType;
|
||||
}
|
||||
|
||||
Type asmType = Type.getObjectType(computeAsmTypeImpl(klass));
|
||||
assert PsiCodegenPredictor.checkPredictedNameFromPsi(klass, asmType);
|
||||
return asmType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String computeAsmTypeImpl(@NotNull ClassDescriptor klass) {
|
||||
DeclarationDescriptor container = klass.getContainingDeclaration();
|
||||
|
||||
String name = SpecialNames.safeIdentifier(klass.getName()).getIdentifier();
|
||||
if (container instanceof PackageFragmentDescriptor) {
|
||||
FqName fqName = ((PackageFragmentDescriptor) container).getFqName();
|
||||
return fqName.isRoot() ? name : fqName.asString().replace('.', '/') + '/' + name;
|
||||
}
|
||||
|
||||
if (container instanceof ScriptDescriptor) {
|
||||
return asmTypeForScriptDescriptor(bindingContext, (ScriptDescriptor) container).getInternalName() + "$" + name;
|
||||
}
|
||||
|
||||
assert container instanceof ClassDescriptor : "Unexpected container: " + container + " for " + klass;
|
||||
|
||||
String containerInternalName = computeAsmTypeImpl((ClassDescriptor) container);
|
||||
switch (klass.getKind()) {
|
||||
case ENUM_ENTRY:
|
||||
return containerInternalName;
|
||||
case CLASS_OBJECT:
|
||||
return containerInternalName + JvmAbi.CLASS_OBJECT_SUFFIX;
|
||||
default:
|
||||
return containerInternalName + "$" + name;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Type mapTraitImpl(@NotNull ClassDescriptor descriptor) {
|
||||
return Type.getObjectType(getAsmType(bindingContext, descriptor).getInternalName() + JvmAbi.TRAIT_IMPL_SUFFIX);
|
||||
return Type.getObjectType(mapType(descriptor).getInternalName() + JvmAbi.TRAIT_IMPL_SUFFIX);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -52,20 +52,13 @@ public class EnumSwitchCodegen extends SwitchCodegen {
|
||||
|
||||
v.swap();
|
||||
|
||||
v.invokevirtual(
|
||||
mapping.getEnumClassInternalName(),
|
||||
"ordinal",
|
||||
Type.getMethodDescriptor(Type.INT_TYPE),
|
||||
false
|
||||
);
|
||||
Type enumType = codegen.getState().getTypeMapper().mapClass(mapping.getEnumClassDescriptor());
|
||||
v.invokevirtual(enumType.getInternalName(), "ordinal", Type.getMethodDescriptor(Type.INT_TYPE), false);
|
||||
v.aload(Type.INT_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processConstant(
|
||||
@NotNull CompileTimeConstant constant,
|
||||
@NotNull Label entryLabel
|
||||
) {
|
||||
protected void processConstant(@NotNull CompileTimeConstant constant, @NotNull Label entryLabel) {
|
||||
assert constant instanceof EnumValue : "guaranteed by usage contract";
|
||||
putTransitionOnce(mapping.getIndexByEntry((EnumValue) constant), entryLabel);
|
||||
}
|
||||
|
||||
@@ -18,11 +18,9 @@ package org.jetbrains.jet.codegen.when;
|
||||
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.codegen.AsmUtil;
|
||||
import org.jetbrains.jet.codegen.ClassBuilder;
|
||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.constants.EnumValue;
|
||||
import org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
@@ -43,16 +41,8 @@ public class MappingClassesForWhenByEnumCodegen {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public void generate(
|
||||
@NotNull List<WhenByEnumsMapping> mappings,
|
||||
@NotNull Type mappingsClass,
|
||||
@NotNull JetFile srcFile
|
||||
) {
|
||||
ClassBuilder cb = state.getFactory().newVisitor(
|
||||
JvmDeclarationOrigin.NO_ORIGIN,
|
||||
mappingsClass,
|
||||
srcFile
|
||||
);
|
||||
public void generate(@NotNull List<WhenByEnumsMapping> mappings, @NotNull Type mappingsClass, @NotNull JetFile srcFile) {
|
||||
ClassBuilder cb = state.getFactory().newVisitor(JvmDeclarationOrigin.NO_ORIGIN, mappingsClass, srcFile);
|
||||
cb.defineClass(
|
||||
srcFile,
|
||||
V1_6,
|
||||
@@ -69,10 +59,7 @@ public class MappingClassesForWhenByEnumCodegen {
|
||||
cb.done();
|
||||
}
|
||||
|
||||
private static void generateFields(
|
||||
@NotNull ClassBuilder cb,
|
||||
@NotNull List<WhenByEnumsMapping> mappings
|
||||
) {
|
||||
private static void generateFields(@NotNull ClassBuilder cb, @NotNull List<WhenByEnumsMapping> mappings) {
|
||||
for (WhenByEnumsMapping mapping : mappings) {
|
||||
cb.newField(
|
||||
JvmDeclarationOrigin.NO_ORIGIN,
|
||||
@@ -84,10 +71,7 @@ public class MappingClassesForWhenByEnumCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
private static void generateInitialization(
|
||||
@NotNull ClassBuilder cb,
|
||||
@NotNull List<WhenByEnumsMapping> mappings
|
||||
) {
|
||||
private void generateInitialization(@NotNull ClassBuilder cb, @NotNull List<WhenByEnumsMapping> mappings) {
|
||||
MethodVisitor mv = cb.newMethod(
|
||||
JvmDeclarationOrigin.NO_ORIGIN,
|
||||
ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY
|
||||
@@ -107,40 +91,26 @@ public class MappingClassesForWhenByEnumCodegen {
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private static void generateInitializationForMapping(
|
||||
private void generateInitializationForMapping(
|
||||
@NotNull ClassBuilder cb,
|
||||
@NotNull InstructionAdapter v,
|
||||
@NotNull WhenByEnumsMapping mapping
|
||||
) {
|
||||
v.invokestatic(
|
||||
mapping.getEnumClassInternalName(), "values",
|
||||
Type.getMethodDescriptor(
|
||||
AsmUtil.getArrayOf(mapping.getEnumClassInternalName())
|
||||
),
|
||||
false
|
||||
);
|
||||
Type enumType = state.getTypeMapper().mapClass(mapping.getEnumClassDescriptor());
|
||||
|
||||
v.invokestatic(enumType.getInternalName(), "values", Type.getMethodDescriptor(Type.getType("[" + enumType.getDescriptor())), false);
|
||||
v.arraylength();
|
||||
|
||||
v.newarray(Type.INT_TYPE);
|
||||
v.putstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR);
|
||||
|
||||
String enumClassDesc = Type.getObjectType(mapping.getEnumClassInternalName()).getDescriptor();
|
||||
|
||||
for (Map.Entry<EnumValue, Integer> item : mapping.enumValuesToIntMapping()) {
|
||||
EnumValue enumEntry = item.getKey();
|
||||
int mappedValue = item.getValue();
|
||||
|
||||
v.getstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR);
|
||||
v.getstatic(
|
||||
mapping.getEnumClassInternalName(),
|
||||
enumEntry.getValue().getName().asString(),
|
||||
enumClassDesc
|
||||
);
|
||||
v.invokevirtual(
|
||||
mapping.getEnumClassInternalName(), "ordinal",
|
||||
Type.getMethodDescriptor(Type.INT_TYPE),
|
||||
false
|
||||
);
|
||||
v.getstatic(enumType.getInternalName(), enumEntry.getValue().getName().asString(), enumType.getDescriptor());
|
||||
v.invokevirtual(enumType.getInternalName(), "ordinal", Type.getMethodDescriptor(Type.INT_TYPE), false);
|
||||
v.iconst(mappedValue);
|
||||
v.astore(Type.INT_TYPE);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.jet.codegen.when;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.constants.EnumValue;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -27,13 +28,17 @@ public class WhenByEnumsMapping {
|
||||
private static final String MAPPINGS_CLASS_NAME_POSTFIX = "$WhenMappings";
|
||||
|
||||
private final Map<EnumValue, Integer> map = new HashMap<EnumValue, Integer>();
|
||||
private final String enumClassInternalName;
|
||||
private final ClassDescriptor enumClassDescriptor;
|
||||
private final String outerClassInternalNameForExpression;
|
||||
private final String mappingsClassInternalName;
|
||||
private final int fieldNumber;
|
||||
|
||||
public WhenByEnumsMapping(String enumClassInternalName, String outerClassInternalNameForExpression, int fieldNumber) {
|
||||
this.enumClassInternalName = enumClassInternalName;
|
||||
public WhenByEnumsMapping(
|
||||
@NotNull ClassDescriptor enumClassDescriptor,
|
||||
@NotNull String outerClassInternalNameForExpression,
|
||||
int fieldNumber
|
||||
) {
|
||||
this.enumClassDescriptor = enumClassDescriptor;
|
||||
this.outerClassInternalNameForExpression = outerClassInternalNameForExpression;
|
||||
this.mappingsClassInternalName = outerClassInternalNameForExpression + MAPPINGS_CLASS_NAME_POSTFIX;
|
||||
this.fieldNumber = fieldNumber;
|
||||
@@ -45,7 +50,7 @@ public class WhenByEnumsMapping {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void putFirstTime(EnumValue value, int index) {
|
||||
public void putFirstTime(@NotNull EnumValue value, int index) {
|
||||
if (!map.containsKey(value)) {
|
||||
map.put(value, index);
|
||||
}
|
||||
@@ -55,22 +60,27 @@ public class WhenByEnumsMapping {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getFieldName() {
|
||||
return MAPPING_ARRAY_FIELD_PREFIX + fieldNumber;
|
||||
}
|
||||
|
||||
public String getEnumClassInternalName() {
|
||||
return enumClassInternalName;
|
||||
@NotNull
|
||||
public ClassDescriptor getEnumClassDescriptor() {
|
||||
return enumClassDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getOuterClassInternalNameForExpression() {
|
||||
return outerClassInternalNameForExpression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getMappingsClassInternalName() {
|
||||
return mappingsClassInternalName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Iterable<Map.Entry<EnumValue, Integer>> enumValuesToIntMapping() {
|
||||
return map.entrySet();
|
||||
}
|
||||
|
||||
@@ -164,6 +164,6 @@ public class BuiltInsSerializer(val out: PrintStream?) {
|
||||
}
|
||||
|
||||
fun getFileName(classDescriptor: ClassDescriptor): String {
|
||||
return BuiltInsSerializationUtil.getClassMetadataPath(DeserializedResolverUtils.getClassId(classDescriptor))
|
||||
return BuiltInsSerializationUtil.getClassMetadataPath(DeserializedResolverUtils.getClassId(classDescriptor))!!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class CommonCompilerArguments {
|
||||
public static final String PLUGIN_OPTION_FORMAT = "<pluginId>:<optionName>=<value>";
|
||||
|
||||
@Argument(value = "nowarn", description = "Generate no warnings")
|
||||
public boolean suppressWarnings;
|
||||
|
||||
@@ -38,6 +40,14 @@ public abstract class CommonCompilerArguments {
|
||||
@Argument(value = "X", description = "Print a synopsis of advanced options")
|
||||
public boolean extraHelp;
|
||||
|
||||
@Argument(value = "Xplugin", description = "Load a plugin from the given classpath")
|
||||
@ValueDescription("<path>")
|
||||
public String[] pluginClasspaths;
|
||||
|
||||
@Argument(value = "P", description = "Pass an option to a plugin")
|
||||
@ValueDescription(PLUGIN_OPTION_FORMAT)
|
||||
public String[] pluginOptions;
|
||||
|
||||
public List<String> freeArgs = new SmartList<String>();
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.jetbrains.jet.lang.resolve.kotlin.incremental.cache.IncrementalCacheP
|
||||
import org.jetbrains.jet.utils.KotlinPaths;
|
||||
import org.jetbrains.jet.utils.KotlinPathsFromHomeDir;
|
||||
import org.jetbrains.jet.utils.PathUtil;
|
||||
import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
@@ -87,6 +88,15 @@ public class K2JVMCompiler extends CLICompiler<K2JVMCompilerArguments> {
|
||||
return INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
try {
|
||||
PluginCliParser.processPluginOptions(arguments, configuration);
|
||||
}
|
||||
catch (CliOptionProcessingException e) {
|
||||
// TODO Print usage?
|
||||
messageCollector.report(CompilerMessageSeverity.ERROR, e.getMessage(), CompilerMessageLocation.NO_LOCATION);
|
||||
return INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (!arguments.script &&
|
||||
arguments.module == null &&
|
||||
arguments.freeArgs.isEmpty() &&
|
||||
|
||||
109
compiler/cli/src/org/jetbrains/jet/cli/jvm/PluginCliParser.kt
Normal file
109
compiler/cli/src/org/jetbrains/jet/cli/jvm/PluginCliParser.kt
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.cli.jvm
|
||||
|
||||
import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
|
||||
import org.jetbrains.jet.cli.common.arguments.CommonCompilerArguments
|
||||
import kotlin.platform.*
|
||||
import java.util.jar.JarFile
|
||||
import java.util.jar.Attributes
|
||||
import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException
|
||||
import java.util.regex.Pattern
|
||||
import org.jetbrains.jet.utils.valuesToMap
|
||||
import org.jetbrains.jet.config.CompilerConfiguration
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.kotlin.compiler.plugin.CliOption
|
||||
|
||||
public object PluginCliParser {
|
||||
|
||||
public val PLUGIN_ARGUMENT_PREFIX: String = "plugin:"
|
||||
|
||||
private fun getCommandLineProcessors(arguments: CommonCompilerArguments): Collection<CommandLineProcessor> {
|
||||
return arguments.pluginClasspaths!!.map {
|
||||
loadCommandLineProcessor(JarFile(it).getManifest()?.getAttributes("org.jetbrains.kotlin.compiler.plugin"))
|
||||
}.filterNotNull()
|
||||
}
|
||||
|
||||
private fun loadCommandLineProcessor(attributes: Attributes?): CommandLineProcessor? {
|
||||
if (attributes == null) return null
|
||||
|
||||
val processorClassName = attributes.getValue("CommandLineProcessor")
|
||||
if (processorClassName == null) return null
|
||||
|
||||
try {
|
||||
val processorClass = Class.forName(processorClassName)
|
||||
return processorClass.newInstance() as CommandLineProcessor
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
throw CliOptionProcessingException("Loading plugin component failed: $processorClassName", e)
|
||||
}
|
||||
}
|
||||
|
||||
[platformStatic]
|
||||
fun processPluginOptions(arguments: CommonCompilerArguments, configuration: CompilerConfiguration) {
|
||||
val optionValuesByPlugin = arguments.pluginOptions!!.map { parsePluginOption(it) }.groupBy {
|
||||
if (it == null) throw CliOptionProcessingException("Wrong plugin option format: $it, should be ${CommonCompilerArguments.PLUGIN_OPTION_FORMAT}")
|
||||
it.optionName
|
||||
}
|
||||
|
||||
val processors = getCommandLineProcessors(arguments)
|
||||
for (processor in processors) {
|
||||
val declaredOptions = processor.pluginOptions.valuesToMap { it.name }
|
||||
val optionsToValues = MultiMap<CliOption, PluginOptionValue>()
|
||||
|
||||
for (optionValue in optionValuesByPlugin[processor.pluginId].orEmpty()) {
|
||||
val option = declaredOptions[optionValue!!.optionName]
|
||||
if (option == null) {
|
||||
throw CliOptionProcessingException("Unsupported plugin option: $optionValue")
|
||||
}
|
||||
optionsToValues.putValue(option, optionValue)
|
||||
}
|
||||
|
||||
for (option in processor.pluginOptions) {
|
||||
val values = optionsToValues[option]
|
||||
if (option.required && values.isEmpty()) {
|
||||
throw CliOptionProcessingException("Required plugin option not present: ${processor.pluginId}:${option.name}")
|
||||
}
|
||||
if (!option.allowMultipleOccurrences && values.size() > 1) {
|
||||
throw CliOptionProcessingException("Multiple values not allowed for plugin option ${processor.pluginId}:${option.name}")
|
||||
}
|
||||
|
||||
for (value in values) {
|
||||
processor.processOption(option, value.value, configuration)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PluginOptionValue(
|
||||
val pluginId: String,
|
||||
val optionName: String,
|
||||
val value: String
|
||||
) {
|
||||
override fun toString() = "$pluginId:$optionName=$value"
|
||||
}
|
||||
|
||||
private fun parsePluginOption(argumentValue: String): PluginOptionValue? {
|
||||
val pattern = Pattern.compile("""^([^:]*):([^=]*)=(.*)$""")
|
||||
val matcher = pattern.matcher(argumentValue)
|
||||
if (matcher.matches()) {
|
||||
return PluginOptionValue(matcher.group(1)!!, matcher.group(2)!!, matcher.group(3)!!)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -97,6 +97,12 @@ public class CliLightClassGenerationSupport extends LightClassGenerationSupport
|
||||
return module;
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
@Nullable
|
||||
public ModuleDescriptorImpl getLightClassModule() {
|
||||
return module;
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public void setModule(@NotNull ModuleDescriptorImpl module) {
|
||||
assert this.module == null : "module already configured: " + module;
|
||||
|
||||
@@ -48,8 +48,10 @@ import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation;
|
||||
import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity;
|
||||
import org.jetbrains.jet.cli.common.messages.MessageCollector;
|
||||
import org.jetbrains.jet.cli.jvm.JVMConfigurationKeys;
|
||||
import org.jetbrains.jet.codegen.extensions.ExpressionCodegenExtension;
|
||||
import org.jetbrains.jet.config.CommonConfigurationKeys;
|
||||
import org.jetbrains.jet.config.CompilerConfiguration;
|
||||
import org.jetbrains.jet.extensions.ExternalDeclarationsProvider;
|
||||
import org.jetbrains.jet.lang.parsing.JetParserDefinition;
|
||||
import org.jetbrains.jet.lang.parsing.JetScriptDefinitionProvider;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
@@ -59,6 +61,7 @@ import org.jetbrains.jet.lang.resolve.lazy.declarations.CliDeclarationProviderFa
|
||||
import org.jetbrains.jet.lang.resolve.lazy.declarations.DeclarationProviderFactoryService;
|
||||
import org.jetbrains.jet.plugin.JetFileType;
|
||||
import org.jetbrains.jet.utils.PathUtil;
|
||||
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@@ -208,6 +211,13 @@ public class JetCoreEnvironment {
|
||||
configuration.getList(CommonConfigurationKeys.SCRIPT_DEFINITIONS_KEY));
|
||||
|
||||
project.registerService(VirtualFileFinderFactory.class, new CliVirtualFileFinderFactory(classPath));
|
||||
|
||||
for (ComponentRegistrar registrar : configuration.getList(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS)) {
|
||||
registrar.registerProjectComponents(project, configuration);
|
||||
}
|
||||
|
||||
ExternalDeclarationsProvider.OBJECT$.registerExtensionPoint(project);
|
||||
ExpressionCodegenExtension.OBJECT$.registerExtensionPoint(project);
|
||||
}
|
||||
|
||||
// made public for Upsource
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiFileFactory;
|
||||
import com.intellij.psi.impl.PsiFileFactoryImpl;
|
||||
@@ -49,8 +50,8 @@ import org.jetbrains.jet.lang.parsing.JetParserDefinition;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.psi.JetScript;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.java.TopDownAnalyzerFacadeForJVM;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
|
||||
import org.jetbrains.jet.lang.resolve.java.TopDownAnalyzerFacadeForJVM;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
|
||||
@@ -77,6 +78,7 @@ import java.util.List;
|
||||
|
||||
import static org.jetbrains.jet.codegen.AsmUtil.asmTypeByFqNameWithoutInnerClasses;
|
||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.registerClassNameForScript;
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
|
||||
|
||||
public class ReplInterpreter {
|
||||
private int lineNumber = 0;
|
||||
@@ -366,8 +368,11 @@ public class ReplInterpreter {
|
||||
ScriptDescriptor earlierDescriptor = pair.first;
|
||||
Type earlierClassType = pair.second;
|
||||
|
||||
registerClassNameForScript(state.getBindingTrace(), earlierDescriptor, earlierClassType);
|
||||
earlierScriptDescriptors.add(earlierDescriptor);
|
||||
PsiElement jetScript = descriptorToDeclaration(earlierDescriptor);
|
||||
if (jetScript != null) {
|
||||
registerClassNameForScript(state.getBindingTrace(), (JetScript) jetScript, earlierClassType);
|
||||
earlierScriptDescriptors.add(earlierDescriptor);
|
||||
}
|
||||
}
|
||||
state.setEarlierScriptsForReplInterpreter(earlierScriptDescriptors);
|
||||
}
|
||||
|
||||
15
compiler/frontend.android/frontend.android.iml
Normal file
15
compiler/frontend.android/frontend.android.iml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="kotlin-runtime" level="project" />
|
||||
<orderEntry type="library" name="intellij-core" level="project" />
|
||||
<orderEntry type="module" module-name="frontend" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
@@ -33,6 +33,10 @@ import org.jetbrains.jet.lang.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.jet.analyzer.ModuleInfo
|
||||
import org.jetbrains.jet.analyzer.ModuleContent
|
||||
import org.jetbrains.jet.di.InjectorForLazyResolveWithJava
|
||||
import org.jetbrains.jet.lang.psi.JetFile
|
||||
import java.util.ArrayList
|
||||
import org.jetbrains.jet.extensions.ExternalDeclarationsProvider
|
||||
import kotlin.platform.platformStatic
|
||||
|
||||
public class JvmResolverForModule(
|
||||
override val lazyResolveSession: ResolveSession,
|
||||
@@ -54,8 +58,9 @@ public object JvmAnalyzerFacade : AnalyzerFacade<JvmResolverForModule, JvmPlatfo
|
||||
resolverForProject: ResolverForProject<M, JvmResolverForModule>
|
||||
): JvmResolverForModule {
|
||||
val (syntheticFiles, moduleContentScope) = moduleContent
|
||||
val filesToAnalyze = getAllFilesToAnalyze(project, syntheticFiles)
|
||||
val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory(
|
||||
project, globalContext.storageManager, syntheticFiles, moduleContentScope
|
||||
project, globalContext.storageManager, filesToAnalyze, moduleContentScope
|
||||
)
|
||||
|
||||
val moduleClassResolver = ModuleClassResolverImpl { javaClass ->
|
||||
@@ -76,4 +81,12 @@ public object JvmAnalyzerFacade : AnalyzerFacade<JvmResolverForModule, JvmPlatfo
|
||||
override val defaultImports = TopDownAnalyzerFacadeForJVM.DEFAULT_IMPORTS
|
||||
override val platformToKotlinClassMap = JavaToKotlinClassMap.getInstance()
|
||||
|
||||
public platformStatic fun getAllFilesToAnalyze(project: Project, baseFiles: Collection<JetFile>): List<JetFile> {
|
||||
val allFiles = ArrayList(baseFiles)
|
||||
for (externalDeclarationsProvider in ExternalDeclarationsProvider.getInstances(project)) {
|
||||
allFiles.addAll(externalDeclarationsProvider.getExternalDeclarations())
|
||||
}
|
||||
return allFiles
|
||||
}
|
||||
|
||||
}
|
||||
@@ -75,6 +75,8 @@ public enum TopDownAnalyzerFacadeForJVM {
|
||||
false
|
||||
);
|
||||
|
||||
List<JetFile> allFiles = JvmAnalyzerFacade.getAllFilesToAnalyze(project, files);
|
||||
|
||||
InjectorForTopDownAnalyzerForJvm injector = new InjectorForTopDownAnalyzerForJvm(project, topDownAnalysisParameters, trace, module);
|
||||
try {
|
||||
List<PackageFragmentProvider> additionalProviders = new ArrayList<PackageFragmentProvider>();
|
||||
@@ -85,7 +87,7 @@ public enum TopDownAnalyzerFacadeForJVM {
|
||||
|
||||
additionalProviders.add(
|
||||
new IncrementalPackageFragmentProvider(
|
||||
files, module, globalContext.getStorageManager(), injector.getDeserializationGlobalContextForJava(),
|
||||
allFiles, module, globalContext.getStorageManager(), injector.getDeserializationGlobalContextForJava(),
|
||||
incrementalCache, moduleId, injector.getJavaDescriptorResolver()
|
||||
)
|
||||
);
|
||||
@@ -93,7 +95,7 @@ public enum TopDownAnalyzerFacadeForJVM {
|
||||
}
|
||||
additionalProviders.add(injector.getJavaDescriptorResolver().getPackageFragmentProvider());
|
||||
|
||||
injector.getTopDownAnalyzer().analyzeFiles(topDownAnalysisParameters, files, additionalProviders);
|
||||
injector.getTopDownAnalyzer().analyzeFiles(topDownAnalysisParameters, allFiles, additionalProviders);
|
||||
return AnalyzeExhaust.success(trace.getBindingContext(), module);
|
||||
}
|
||||
finally {
|
||||
|
||||
@@ -81,8 +81,9 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass {
|
||||
@NotNull
|
||||
protected abstract byte[] getFileContents();
|
||||
|
||||
// TODO public to be accessible in class object of subclass, workaround for KT-3974
|
||||
@Nullable
|
||||
protected static <T extends FileBasedKotlinClass> T create(
|
||||
public static <T extends FileBasedKotlinClass> T create(
|
||||
@NotNull byte[] fileContents,
|
||||
@NotNull Function3<ClassId, KotlinClassHeader, InnerClassesInfo, T> factory
|
||||
) {
|
||||
|
||||
@@ -56,8 +56,12 @@ public class PackagePartClassUtils {
|
||||
String fileName = FileUtil.getNameWithoutExtension(PathUtil.getFileName(file.getName()));
|
||||
|
||||
// path hashCode to prevent same name / different path collision
|
||||
String srcName = facadeFqName.shortName().asString() + "-" + replaceSpecialSymbols(fileName) + "-" + Integer.toHexString(
|
||||
getPathHashCode(file));
|
||||
String srcName = String.format(
|
||||
"%s$%s$%08x",
|
||||
facadeFqName.shortName().asString(),
|
||||
replaceSpecialSymbols(fileName),
|
||||
getPathHashCode(file)
|
||||
);
|
||||
|
||||
return facadeFqName.parent().child(Name.identifier(srcName));
|
||||
}
|
||||
|
||||
@@ -23,17 +23,17 @@ import org.jetbrains.jet.lang.resolve.java.JvmClassName
|
||||
import java.util.HashMap
|
||||
import java.io.File
|
||||
|
||||
public fun IncrementalCache.getPackagesWithRemovedFiles(compiledSourceFiles: Collection<JetFile>): Collection<FqName> {
|
||||
return getRemovedPackageParts(compiledSourceFiles).map { it.getFqNameForClassNameWithoutDollars().parent() }
|
||||
public fun IncrementalCache.getPackagesWithRemovedFiles(sourceFilesToCompile: Collection<JetFile>): Collection<FqName> {
|
||||
return getRemovedPackageParts(sourceFilesToCompile).map { it.getPackageFqName() }
|
||||
}
|
||||
|
||||
public fun IncrementalCache.getRemovedPackageParts(compiledSourceFiles: Collection<JetFile>): Collection<JvmClassName> {
|
||||
val compiledSourceFilesToFqName = HashMap<File, String>()
|
||||
for (sourceFile in compiledSourceFiles) {
|
||||
compiledSourceFilesToFqName[File(sourceFile.getVirtualFile()!!.getPath())] = sourceFile.getPackageFqName().asString()
|
||||
public fun IncrementalCache.getRemovedPackageParts(sourceFilesToCompile: Collection<JetFile>): Collection<JvmClassName> {
|
||||
val sourceFilesToFqName = HashMap<File, String>()
|
||||
for (sourceFile in sourceFilesToCompile) {
|
||||
sourceFilesToFqName[File(sourceFile.getVirtualFile()!!.getPath())] = sourceFile.getPackageFqName().asString()
|
||||
}
|
||||
|
||||
return getRemovedPackageParts(compiledSourceFilesToFqName).map { JvmClassName.byInternalName(it) }
|
||||
return getRemovedPackageParts(sourceFilesToFqName).map { JvmClassName.byInternalName(it) }
|
||||
}
|
||||
|
||||
public fun IncrementalCache.getPackageData(fqName: FqName): ByteArray? {
|
||||
|
||||
@@ -56,6 +56,7 @@ public class IncrementalPackageFragmentProvider(
|
||||
).toSet()
|
||||
val fqNameToSubFqNames = MultiMap<FqName, FqName>()
|
||||
val fqNameToPackageFragment = HashMap<FqName, PackageFragmentDescriptor>()
|
||||
val fqNamesToLoad: Set<FqName>
|
||||
|
||||
;{
|
||||
fun createPackageFragment(fqName: FqName) {
|
||||
@@ -72,13 +73,12 @@ public class IncrementalPackageFragmentProvider(
|
||||
fqNameToPackageFragment[fqName] = IncrementalPackageFragment(fqName)
|
||||
}
|
||||
|
||||
for (source in PackagePartClassUtils.getPackageFilesWithCallables(sourceFiles)) {
|
||||
createPackageFragment(source.getPackageFqName())
|
||||
}
|
||||
fqNamesToLoad = (
|
||||
PackagePartClassUtils.getPackageFilesWithCallables(sourceFiles).map { it.getPackageFqName() }
|
||||
+ incrementalCache.getPackagesWithRemovedFiles(sourceFiles)
|
||||
).toSet()
|
||||
|
||||
for (fqName in incrementalCache.getPackagesWithRemovedFiles(sourceFiles)) {
|
||||
createPackageFragment(fqName)
|
||||
}
|
||||
fqNamesToLoad.forEach { createPackageFragment(it) }
|
||||
}
|
||||
|
||||
override fun getSubPackagesOf(fqName: FqName): Collection<FqName> {
|
||||
@@ -95,12 +95,17 @@ public class IncrementalPackageFragmentProvider(
|
||||
get() = this@IncrementalPackageFragmentProvider.moduleId
|
||||
|
||||
val _memberScope: NotNullLazyValue<JetScope> = storageManager.createLazyValue {
|
||||
val packageDataBytes = incrementalCache.getPackageData(fqName)
|
||||
if (packageDataBytes == null) {
|
||||
if (fqName !in fqNamesToLoad) {
|
||||
JetScope.EMPTY
|
||||
}
|
||||
else {
|
||||
IncrementalPackageScope(JavaProtoBufUtil.readPackageDataFrom(packageDataBytes))
|
||||
val packageDataBytes = incrementalCache.getPackageData(fqName)
|
||||
if (packageDataBytes == null) {
|
||||
JetScope.EMPTY
|
||||
}
|
||||
else {
|
||||
IncrementalPackageScope(JavaProtoBufUtil.readPackageDataFrom(packageDataBytes))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.util.HashMap
|
||||
import java.io.File
|
||||
|
||||
public trait IncrementalCache {
|
||||
public fun getRemovedPackageParts(compiledSourceFilesToFqName: Map<File, String>): Collection<String>
|
||||
public fun getRemovedPackageParts(sourceFilesToCompileAndFqNames: Map<File, String>): Collection<String>
|
||||
|
||||
public fun getPackageData(fqName: String): ByteArray?
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<orderEntry type="module" module-name="util" />
|
||||
<orderEntry type="module" module-name="serialization" />
|
||||
<orderEntry type="module" module-name="descriptors" exported="" />
|
||||
<orderEntry type="module" module-name="plugin-api" exported="" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
||||
@@ -38,15 +38,23 @@ public trait ResolverForModule {
|
||||
public trait ResolverForProject<M : ModuleInfo, R : ResolverForModule> {
|
||||
public fun resolverForModule(moduleInfo: M): R
|
||||
public fun descriptorForModule(moduleInfo: M): ModuleDescriptor
|
||||
val allModules: Collection<M>
|
||||
}
|
||||
|
||||
public class EmptyResolverForProject<M : ModuleInfo, R : ResolverForModule> : ResolverForProject<M, R> {
|
||||
override fun resolverForModule(moduleInfo: M): R = throw IllegalStateException("Should not be called for $moduleInfo")
|
||||
override fun descriptorForModule(moduleInfo: M) = throw IllegalStateException("Should not be called for $moduleInfo")
|
||||
override val allModules: Collection<M> = listOf()
|
||||
}
|
||||
|
||||
public class ResolverForProjectImpl<M : ModuleInfo, R : ResolverForModule>(
|
||||
val descriptorByModule: Map<M, ModuleDescriptorImpl>
|
||||
val descriptorByModule: Map<M, ModuleDescriptorImpl>,
|
||||
val delegateResolver: ResolverForProject<M, R> = EmptyResolverForProject()
|
||||
) : ResolverForProject<M, R> {
|
||||
val resolverByModuleDescriptor: MutableMap<ModuleDescriptor, R> = HashMap()
|
||||
|
||||
private val allModules: Collection<M> by Delegates.lazy {
|
||||
descriptorByModule.keySet()
|
||||
override val allModules: Collection<M> by Delegates.lazy {
|
||||
(descriptorByModule.keySet() + delegateResolver.allModules).toSet()
|
||||
}
|
||||
|
||||
private fun assertCorrectModuleInfo(moduleInfo: M) {
|
||||
@@ -57,13 +65,13 @@ public class ResolverForProjectImpl<M : ModuleInfo, R : ResolverForModule>(
|
||||
|
||||
override fun resolverForModule(moduleInfo: M): R {
|
||||
assertCorrectModuleInfo(moduleInfo)
|
||||
val descriptor = descriptorByModule[moduleInfo]!!
|
||||
val descriptor = descriptorByModule[moduleInfo] ?: return delegateResolver.resolverForModule(moduleInfo)
|
||||
return resolverByModuleDescriptor[descriptor]!!
|
||||
}
|
||||
|
||||
override fun descriptorForModule(moduleInfo: M): ModuleDescriptorImpl {
|
||||
assertCorrectModuleInfo(moduleInfo)
|
||||
return descriptorByModule[moduleInfo]!!
|
||||
return descriptorByModule[moduleInfo] ?: return delegateResolver.descriptorForModule(moduleInfo) as ModuleDescriptorImpl
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +119,8 @@ public trait AnalyzerFacade<out A : ResolverForModule, in P : PlatformAnalysisPa
|
||||
project: Project,
|
||||
modules: Collection<M>,
|
||||
modulesContent: (M) -> ModuleContent,
|
||||
platformParameters: P
|
||||
platformParameters: P,
|
||||
delegateResolver: ResolverForProject<M, A> = EmptyResolverForProject()
|
||||
): ResolverForProject<M, A> {
|
||||
|
||||
fun createResolverForProject(): ResolverForProjectImpl<M, A> {
|
||||
@@ -120,7 +129,7 @@ public trait AnalyzerFacade<out A : ResolverForModule, in P : PlatformAnalysisPa
|
||||
module ->
|
||||
descriptorByModule[module] = ModuleDescriptorImpl(module.name, defaultImports, platformToKotlinClassMap)
|
||||
}
|
||||
return ResolverForProjectImpl(descriptorByModule)
|
||||
return ResolverForProjectImpl(descriptorByModule, delegateResolver)
|
||||
}
|
||||
|
||||
val resolverForProject = createResolverForProject()
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.extensions
|
||||
|
||||
import org.jetbrains.jet.lang.psi.JetFile
|
||||
|
||||
public trait ExternalDeclarationsProvider {
|
||||
class object : ProjectExtensionDescriptor<ExternalDeclarationsProvider>(
|
||||
"org.jetbrains.kotlin.externalDeclarationsProvider",
|
||||
javaClass<ExternalDeclarationsProvider>()
|
||||
)
|
||||
|
||||
public fun getExternalDeclarations(): Collection<JetFile>
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.extensions
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.extensions.Extensions
|
||||
import com.intellij.openapi.extensions.ExtensionPoint
|
||||
|
||||
public open class ProjectExtensionDescriptor<T>(name: String, private val extensionClass: Class<T>) {
|
||||
public val extensionPointName: ExtensionPointName<T> = ExtensionPointName.create(name)!!
|
||||
|
||||
public fun registerExtensionPoint(project: Project) {
|
||||
Extensions.getArea(project).registerExtensionPoint(
|
||||
extensionPointName.getName()!!,
|
||||
extensionClass.getName(),
|
||||
ExtensionPoint.Kind.INTERFACE
|
||||
)
|
||||
}
|
||||
|
||||
public fun registerExtension(project: Project, extension: T) {
|
||||
Extensions.getArea(project).getExtensionPoint(extensionPointName).registerExtension(extension)
|
||||
}
|
||||
|
||||
public fun getInstances(project: Project): Collection<T> {
|
||||
val projectArea = Extensions.getArea(project)
|
||||
if (!projectArea.hasExtensionPoint(extensionPointName.getName()!!)) return listOf()
|
||||
|
||||
return projectArea.getExtensionPoint(extensionPointName).getExtensions().toList()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,5 @@ public class ReturnValueInstruction(
|
||||
return ReturnValueInstruction((element as JetExpression), lexicalScope, newLabel, returnedValue)
|
||||
}
|
||||
|
||||
public val resultExpression: JetExpression =
|
||||
element.let{ if (it is JetReturnExpression) it.getReturnedExpression()!! else element as JetExpression }
|
||||
public val returnExpressionIfAny: JetReturnExpression? = element as? JetReturnExpression
|
||||
}
|
||||
|
||||
@@ -446,6 +446,7 @@ public interface Errors {
|
||||
DiagnosticFactory2<JetExpression, String, Collection<? extends ResolvedCall<?>>> DELEGATE_SPECIAL_FUNCTION_AMBIGUITY = DiagnosticFactory2.create(ERROR);
|
||||
DiagnosticFactory2<JetExpression, String, Collection<? extends ResolvedCall<?>>> DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE = DiagnosticFactory2.create(ERROR);
|
||||
DiagnosticFactory3<JetExpression, String, JetType, JetType> DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH = DiagnosticFactory3.create(ERROR);
|
||||
DiagnosticFactory2<JetExpression, String, Collection<? extends ResolvedCall<?>>> DELEGATE_PD_METHOD_NONE_APPLICABLE = DiagnosticFactory2.create(WARNING);
|
||||
|
||||
DiagnosticFactory1<JetSimpleNameExpression, JetType> COMPARE_TO_TYPE_MISMATCH = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
|
||||
@@ -285,6 +285,7 @@ public class DefaultErrorMessages {
|
||||
STRING, AMBIGUOUS_CALLS);
|
||||
MAP.put(DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH, "The ''{0}'' function of property delegate is expected to return ''{1}'', but returns ''{2}''",
|
||||
STRING, RENDER_TYPE, RENDER_TYPE);
|
||||
MAP.put(DELEGATE_PD_METHOD_NONE_APPLICABLE, "''{0}'' method may be missing. None of the following functions will be called: {1}", STRING, AMBIGUOUS_CALLS);
|
||||
|
||||
MAP.put(COMPARE_TO_TYPE_MISMATCH, "''compareTo()'' must return kotlin.Int, but returns {0}", RENDER_TYPE);
|
||||
|
||||
|
||||
@@ -216,9 +216,8 @@ public class JetPsiFactory(private val project: Project) {
|
||||
return createClass("class A(){}").getBody()!!
|
||||
}
|
||||
|
||||
public fun createParameter(name: String, `type`: String): JetParameter {
|
||||
val function = createFunction("fun foo(" + name + " : " + `type` + ") {}")
|
||||
return function.getValueParameters().first()
|
||||
public fun createParameter(text : String): JetParameter {
|
||||
return createClass("class A($text)").getPrimaryConstructorParameters().first()
|
||||
}
|
||||
|
||||
public fun createParameterList(text: String): JetParameterList {
|
||||
|
||||
@@ -335,3 +335,14 @@ public fun JetExpression.isFunctionLiteralOutsideParentheses(): Boolean {
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
public fun PsiElement.siblings(forward: Boolean = true, withItself: Boolean = true): Stream<PsiElement> {
|
||||
val stepFun = if (forward) { (e: PsiElement) -> e.getNextSibling() } else { (e: PsiElement) -> e.getPrevSibling() }
|
||||
val stream = stream(this, stepFun)
|
||||
return if (withItself) stream else stream.drop(1)
|
||||
}
|
||||
|
||||
public fun PsiElement.parents(withItself: Boolean = true): Stream<PsiElement> {
|
||||
val stream = stream(this) { if (it is PsiFile) null else it.getParent() }
|
||||
return if (withItself) stream else stream.drop(1)
|
||||
}
|
||||
@@ -113,6 +113,8 @@ public interface BindingContext {
|
||||
WritableSlice<PropertyAccessorDescriptor, ResolvedCall<FunctionDescriptor>> DELEGATED_PROPERTY_RESOLVED_CALL = Slices.createSimpleSlice();
|
||||
WritableSlice<PropertyAccessorDescriptor, Call> DELEGATED_PROPERTY_CALL = Slices.createSimpleSlice();
|
||||
|
||||
WritableSlice<PropertyDescriptor, ResolvedCall<FunctionDescriptor>> DELEGATED_PROPERTY_PD_RESOLVED_CALL = Slices.createSimpleSlice();
|
||||
|
||||
WritableSlice<JetMultiDeclarationEntry, ResolvedCall<FunctionDescriptor>> COMPONENT_RESOLVED_CALL = Slices.createSimpleSlice();
|
||||
|
||||
WritableSlice<JetExpression, ResolvedCall<FunctionDescriptor>> INDEXED_LVALUE_GET = Slices.createSimpleSlice();
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.jetbrains.jet.lang.resolve;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.containers.Queue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -26,17 +25,13 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.ContextDependency;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.SimpleResolutionContext;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
|
||||
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.*;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
import org.jetbrains.jet.lang.types.expressions.DataFlowUtils;
|
||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
||||
import org.jetbrains.jet.lexer.JetModifierKeywordToken;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.jetbrains.jet.util.Box;
|
||||
import org.jetbrains.jet.util.ReenteringLazyValueComputationException;
|
||||
@@ -553,6 +548,9 @@ public class BodyResolver {
|
||||
delegatedPropertyResolver.resolveDelegatedPropertySetMethod(propertyDescriptor, delegateExpression, delegateType,
|
||||
trace, accessorScope);
|
||||
}
|
||||
|
||||
delegatedPropertyResolver.resolveDelegatedPropertyPDMethod(propertyDescriptor, delegateExpression, delegateType,
|
||||
trace, accessorScope);
|
||||
}
|
||||
|
||||
public void resolvePropertyInitializer(
|
||||
|
||||
@@ -61,6 +61,8 @@ public class DelegatedPropertyResolver {
|
||||
@NotNull
|
||||
private CallResolver callResolver;
|
||||
|
||||
private static final String PD_METHOD_NAME = "propertyDelegated";
|
||||
|
||||
@Inject
|
||||
public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) {
|
||||
this.expressionTypingServices = expressionTypingServices;
|
||||
@@ -115,6 +117,55 @@ public class DelegatedPropertyResolver {
|
||||
resolveDelegatedPropertyConventionMethod(propertyDescriptor, delegateExpression, delegateType, trace, scope, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JetExpression createExpressionForPropertyMetadata(
|
||||
@NotNull JetPsiFactory psiFactory,
|
||||
@NotNull PropertyDescriptor propertyDescriptor
|
||||
) {
|
||||
return psiFactory.createExpression(KotlinBuiltIns.getInstance().getPropertyMetadataImpl().getName().asString() +
|
||||
"(\"" +
|
||||
propertyDescriptor.getName().asString() +
|
||||
"\")");
|
||||
}
|
||||
|
||||
public void resolveDelegatedPropertyPDMethod(
|
||||
@NotNull PropertyDescriptor propertyDescriptor,
|
||||
@NotNull JetExpression delegateExpression,
|
||||
@NotNull JetType delegateType,
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull JetScope scope
|
||||
) {
|
||||
TemporaryBindingTrace traceToResolvePDMethod = TemporaryBindingTrace.create(trace, "Trace to resolve propertyDelegated method in delegated property");
|
||||
ExpressionTypingContext context = ExpressionTypingContext.newContext(
|
||||
expressionTypingServices, traceToResolvePDMethod, scope,
|
||||
DataFlowInfo.EMPTY, TypeUtils.NO_EXPECTED_TYPE);
|
||||
|
||||
List<JetExpression> arguments = Lists.newArrayList();
|
||||
JetPsiFactory psiFactory = JetPsiFactory(delegateExpression);
|
||||
arguments.add(createExpressionForPropertyMetadata(psiFactory, propertyDescriptor));
|
||||
Name functionName = Name.identifier(PD_METHOD_NAME);
|
||||
JetReferenceExpression fakeCalleeExpression = psiFactory.createSimpleName(functionName.asString());
|
||||
ExpressionReceiver receiver = new ExpressionReceiver(delegateExpression, delegateType);
|
||||
Call call = CallMaker.makeCallWithExpressions(fakeCalleeExpression, receiver, null, fakeCalleeExpression, arguments, Call.CallType.DEFAULT);
|
||||
|
||||
OverloadResolutionResults<FunctionDescriptor> functionResults =
|
||||
callResolver.resolveCallWithGivenName(context, call, fakeCalleeExpression, functionName);
|
||||
|
||||
if (!functionResults.isSuccess()) {
|
||||
String expectedFunction = renderCall(call, traceToResolvePDMethod.getBindingContext());
|
||||
if (functionResults.isIncomplete() || functionResults.isSingleResult() ||
|
||||
functionResults.getResultCode() == OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES) {
|
||||
trace.report(DELEGATE_PD_METHOD_NONE_APPLICABLE.on(delegateExpression, expectedFunction, functionResults.getResultingCalls()));
|
||||
} else if (functionResults.isAmbiguity()) {
|
||||
trace.report(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY
|
||||
.on(delegateExpression, expectedFunction, functionResults.getResultingCalls()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
trace.record(DELEGATED_PROPERTY_PD_RESOLVED_CALL, propertyDescriptor, functionResults.getResultingCall());
|
||||
}
|
||||
|
||||
/* Resolve get() or set() methods from delegate */
|
||||
private void resolveDelegatedPropertyConventionMethod(
|
||||
@NotNull PropertyDescriptor propertyDescriptor,
|
||||
@@ -179,10 +230,7 @@ public class DelegatedPropertyResolver {
|
||||
JetPsiFactory psiFactory = JetPsiFactory(delegateExpression);
|
||||
arguments.add(psiFactory.createExpression(hasThis ? "this" : "null"));
|
||||
|
||||
arguments.add(psiFactory.createExpression(KotlinBuiltIns.getInstance().getPropertyMetadataImpl().getName().asString() +
|
||||
"(\"" +
|
||||
propertyDescriptor.getName().asString() +
|
||||
"\")"));
|
||||
arguments.add(createExpressionForPropertyMetadata(psiFactory, propertyDescriptor));
|
||||
|
||||
if (!isGet) {
|
||||
JetReferenceExpression fakeArgument = (JetReferenceExpression) createFakeExpressionOfType(expressionTypingServices.getProject(), trace,
|
||||
|
||||
@@ -421,7 +421,7 @@ public class DescriptorResolver {
|
||||
Annotations.EMPTY,
|
||||
COPY_METHOD_NAME,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
SourceElement.NO_SOURCE
|
||||
classDescriptor.getSource()
|
||||
);
|
||||
|
||||
List<ValueParameterDescriptor> parameterDescriptors = Lists.newArrayList();
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.jet.lang.resolve;
|
||||
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
||||
import org.jetbrains.jet.renderer.DescriptorRendererBuilder;
|
||||
|
||||
@@ -69,66 +70,85 @@ public class MemberComparator implements Comparator<DeclarationDescriptor> {
|
||||
return namesCompareTo;
|
||||
}
|
||||
|
||||
if (!(o1 instanceof CallableDescriptor) || !(o2 instanceof CallableDescriptor)) {
|
||||
assert false : "Descriptors must be callable:\n" + o1 + "\n" + o2;
|
||||
}
|
||||
if (o1 instanceof CallableDescriptor && o2 instanceof CallableDescriptor) {
|
||||
CallableDescriptor c1 = (CallableDescriptor) o1;
|
||||
CallableDescriptor c2 = (CallableDescriptor) o2;
|
||||
|
||||
CallableDescriptor c1 = (CallableDescriptor)o1;
|
||||
CallableDescriptor c2 = (CallableDescriptor)o2;
|
||||
ReceiverParameterDescriptor c1ReceiverParameter = c1.getReceiverParameter();
|
||||
ReceiverParameterDescriptor c2ReceiverParameter = c2.getReceiverParameter();
|
||||
assert (c1ReceiverParameter != null) == (c2ReceiverParameter != null);
|
||||
if (c1ReceiverParameter != null) {
|
||||
String r1 = RENDERER.renderType(c1ReceiverParameter.getType());
|
||||
String r2 = RENDERER.renderType(c2ReceiverParameter.getType());
|
||||
int receiversCompareTo = r1.compareTo(r2);
|
||||
if (receiversCompareTo != 0) {
|
||||
return receiversCompareTo;
|
||||
}
|
||||
}
|
||||
|
||||
ReceiverParameterDescriptor c1ReceiverParameter = c1.getReceiverParameter();
|
||||
ReceiverParameterDescriptor c2ReceiverParameter = c2.getReceiverParameter();
|
||||
assert (c1ReceiverParameter != null) == (c2ReceiverParameter != null);
|
||||
if (c1ReceiverParameter != null) {
|
||||
String r1 = RENDERER.renderType(c1ReceiverParameter.getType());
|
||||
String r2 = RENDERER.renderType(c2ReceiverParameter.getType());
|
||||
int receiversCompareTo = r1.compareTo(r2);
|
||||
if (receiversCompareTo != 0) {
|
||||
return receiversCompareTo;
|
||||
List<ValueParameterDescriptor> c1ValueParameters = c1.getValueParameters();
|
||||
List<ValueParameterDescriptor> c2ValueParameters = c2.getValueParameters();
|
||||
for (int i = 0; i < Math.min(c1ValueParameters.size(), c2ValueParameters.size()); i++) {
|
||||
String p1 = RENDERER.renderType(c1ValueParameters.get(i).getType());
|
||||
String p2 = RENDERER.renderType(c2ValueParameters.get(i).getType());
|
||||
int parametersCompareTo = p1.compareTo(p2);
|
||||
if (parametersCompareTo != 0) {
|
||||
return parametersCompareTo;
|
||||
}
|
||||
}
|
||||
|
||||
int valueParametersNumberCompareTo = c1ValueParameters.size() - c2ValueParameters.size();
|
||||
if (valueParametersNumberCompareTo != 0) {
|
||||
return valueParametersNumberCompareTo;
|
||||
}
|
||||
|
||||
List<TypeParameterDescriptor> c1TypeParameters = c1.getTypeParameters();
|
||||
List<TypeParameterDescriptor> c2TypeParameters = c2.getTypeParameters();
|
||||
for (int i = 0; i < Math.min(c1TypeParameters.size(), c2TypeParameters.size()); i++) {
|
||||
String p1 = RENDERER.renderType(c1TypeParameters.get(i).getUpperBoundsAsType());
|
||||
String p2 = RENDERER.renderType(c2TypeParameters.get(i).getUpperBoundsAsType());
|
||||
int parametersCompareTo = p1.compareTo(p2);
|
||||
if (parametersCompareTo != 0) {
|
||||
return parametersCompareTo;
|
||||
}
|
||||
}
|
||||
|
||||
int typeParametersCompareTo = c1TypeParameters.size() - c2TypeParameters.size();
|
||||
if (typeParametersCompareTo != 0) {
|
||||
return typeParametersCompareTo;
|
||||
}
|
||||
|
||||
if (c1 instanceof CallableMemberDescriptor && c2 instanceof CallableMemberDescriptor) {
|
||||
CallableMemberDescriptor.Kind c1Kind = ((CallableMemberDescriptor) c1).getKind();
|
||||
CallableMemberDescriptor.Kind c2Kind = ((CallableMemberDescriptor) c2).getKind();
|
||||
int kindsCompareTo = c1Kind.ordinal() - c2Kind.ordinal();
|
||||
if (kindsCompareTo != 0) {
|
||||
return kindsCompareTo;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (o1 instanceof ClassDescriptor && o2 instanceof ClassDescriptor) {
|
||||
ClassDescriptor class1 = (ClassDescriptor) o1;
|
||||
ClassDescriptor class2 = (ClassDescriptor) o2;
|
||||
|
||||
List<ValueParameterDescriptor> c1ValueParameters = c1.getValueParameters();
|
||||
List<ValueParameterDescriptor> c2ValueParameters = c2.getValueParameters();
|
||||
for (int i = 0; i < Math.min(c1ValueParameters.size(), c2ValueParameters.size()); i++) {
|
||||
String p1 = RENDERER.renderType(c1ValueParameters.get(i).getType());
|
||||
String p2 = RENDERER.renderType(c2ValueParameters.get(i).getType());
|
||||
int parametersCompareTo = p1.compareTo(p2);
|
||||
if (parametersCompareTo != 0) {
|
||||
return parametersCompareTo;
|
||||
if (class1.getKind().ordinal() != class2.getKind().ordinal()) {
|
||||
return class1.getKind().ordinal() - class2.getKind().ordinal();
|
||||
}
|
||||
}
|
||||
|
||||
int valueParametersNumberCompareTo = c1ValueParameters.size() - c2ValueParameters.size();
|
||||
if (valueParametersNumberCompareTo != 0) {
|
||||
return valueParametersNumberCompareTo;
|
||||
else {
|
||||
throw new AssertionError(String.format(
|
||||
"Unsupported pair of descriptors:\n'" +
|
||||
"%s' Class: %s\n" +
|
||||
"%s' Class: %s",
|
||||
o1, o1.getClass(), o2, o2.getClass()));
|
||||
}
|
||||
|
||||
List<TypeParameterDescriptor> c1TypeParameters = c1.getTypeParameters();
|
||||
List<TypeParameterDescriptor> c2TypeParameters = c2.getTypeParameters();
|
||||
for (int i = 0; i < Math.min(c1TypeParameters.size(), c2TypeParameters.size()); i++) {
|
||||
String p1 = RENDERER.renderType(c1TypeParameters.get(i).getUpperBoundsAsType());
|
||||
String p2 = RENDERER.renderType(c2TypeParameters.get(i).getUpperBoundsAsType());
|
||||
int parametersCompareTo = p1.compareTo(p2);
|
||||
if (parametersCompareTo != 0) {
|
||||
return parametersCompareTo;
|
||||
}
|
||||
}
|
||||
int renderDiff = RENDERER.render(o1).compareTo(RENDERER.render(o2));
|
||||
if (renderDiff != 0) return renderDiff;
|
||||
|
||||
int typeParametersCompareTo = c1TypeParameters.size() - c2TypeParameters.size();
|
||||
if (typeParametersCompareTo != 0) {
|
||||
return typeParametersCompareTo;
|
||||
}
|
||||
Name firstModuleName = DescriptorUtils.getContainingModule(o1).getName();
|
||||
Name secondModuleName = DescriptorUtils.getContainingModule(o2).getName();
|
||||
|
||||
if (c1 instanceof CallableMemberDescriptor && c2 instanceof CallableMemberDescriptor) {
|
||||
CallableMemberDescriptor.Kind c1Kind = ((CallableMemberDescriptor) c1).getKind();
|
||||
CallableMemberDescriptor.Kind c2Kind = ((CallableMemberDescriptor) c2).getKind();
|
||||
int kindsCompareTo = c1Kind.ordinal() - c2Kind.ordinal();
|
||||
if (kindsCompareTo != 0) {
|
||||
return kindsCompareTo;
|
||||
}
|
||||
}
|
||||
|
||||
return RENDERER.render(o1).compareTo(RENDERER.render(o2));
|
||||
return firstModuleName.compareTo(secondModuleName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ public class AutoCastUtils {
|
||||
|
||||
private AutoCastUtils() {}
|
||||
|
||||
@NotNull
|
||||
public static List<JetType> getAutoCastVariants(
|
||||
@NotNull ReceiverValue receiverToCast,
|
||||
@NotNull ResolutionContext context
|
||||
@@ -51,6 +52,7 @@ public class AutoCastUtils {
|
||||
return getAutoCastVariants(receiverToCast, context.trace.getBindingContext(), context.dataFlowInfo);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<JetType> getAutoCastVariants(
|
||||
@NotNull ReceiverValue receiverToCast,
|
||||
@NotNull BindingContext bindingContext,
|
||||
|
||||
@@ -36,6 +36,7 @@ import java.util.Set;
|
||||
public final class JetScopeUtils {
|
||||
private JetScopeUtils() {}
|
||||
|
||||
@NotNull
|
||||
public static List<ReceiverValue> getImplicitReceiversHierarchyValues(@NotNull JetScope scope) {
|
||||
Collection<ReceiverParameterDescriptor> hierarchy = scope.getImplicitReceiversHierarchy();
|
||||
|
||||
@@ -56,6 +57,7 @@ public final class JetScopeUtils {
|
||||
* @param scope Scope for query extensions.
|
||||
* @return extension descriptors.
|
||||
*/
|
||||
@NotNull
|
||||
public static Collection<CallableDescriptor> getAllExtensions(@NotNull JetScope scope) {
|
||||
Set<CallableDescriptor> result = Sets.newHashSet();
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user