mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-18 00:21:29 +00:00
Compare commits
2 Commits
abannykh/v
...
stdlib/sco
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
674f60beb8 | ||
|
|
c236697977 |
2
.idea/artifacts/KotlinPlugin.xml
generated
2
.idea/artifacts/KotlinPlugin.xml
generated
@@ -10,7 +10,6 @@
|
||||
<root id="root">
|
||||
<element id="directory" name="lib">
|
||||
<element id="archive" name="kotlin-plugin.jar">
|
||||
<element id="extracted-dir" path="$PROJECT_DIR$/dependencies/cli-parser-1.1.2.jar" path-in-jar="/" />
|
||||
<element id="module-output" name="backend" />
|
||||
<element id="module-output" name="frontend" />
|
||||
<element id="module-output" name="descriptors" />
|
||||
@@ -25,7 +24,6 @@
|
||||
<element id="module-output" name="js.parser" />
|
||||
<element id="module-output" name="cli-common" />
|
||||
<element id="module-output" name="idea-jps-common" />
|
||||
<element id="module-output" name="build-common" />
|
||||
<element id="module-output" name="preloader" />
|
||||
<element id="module-output" name="deserialization" />
|
||||
<element id="module-output" name="backend-common" />
|
||||
|
||||
1
.idea/dictionaries/Nikolay_Krasko.xml
generated
1
.idea/dictionaries/Nikolay_Krasko.xml
generated
@@ -2,7 +2,6 @@
|
||||
<dictionary name="Nikolay.Krasko">
|
||||
<words>
|
||||
<w>accessors</w>
|
||||
<w>crossinline</w>
|
||||
<w>fqname</w>
|
||||
<w>goto</w>
|
||||
<w>gradle</w>
|
||||
|
||||
4
.idea/kotlinc.xml
generated
4
.idea/kotlinc.xml
generated
@@ -1,9 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KotlinCommonCompilerArguments">
|
||||
<option name="languageVersion" value="1.1" />
|
||||
<option name="apiVersion" value="1.1" />
|
||||
</component>
|
||||
<component name="KotlinCompilerSettings">
|
||||
<option name="additionalArguments" value="-version -Xallow-kotlin-package -Xskip-metadata-version-check" />
|
||||
</component>
|
||||
|
||||
2
.idea/libraries/uast_java.xml
generated
2
.idea/libraries/uast_java.xml
generated
@@ -3,13 +3,11 @@
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/uast-common.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/uast-java.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/uast-tests.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/uast-common-sources.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/uast-java-sources.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/dependencies/uast-tests-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -49,7 +49,7 @@
|
||||
<component name="ProjectResources">
|
||||
<default-html-doctype>http://www.w3.org/1999/xhtml</default-html-doctype>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" default="false" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" default="false" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
<component name="SuppressABINotification">
|
||||
|
||||
28
.idea/runConfigurations/Java_8_Tests_on_JDK_9.xml
generated
28
.idea/runConfigurations/Java_8_Tests_on_JDK_9.xml
generated
@@ -1,28 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Java 8 Tests on JDK 9" type="JUnit" factoryName="JUnit">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea">
|
||||
<pattern>
|
||||
<option name="PATTERN" value="org.jetbrains.kotlin.*" />
|
||||
<option name="ENABLED" value="true" />
|
||||
</pattern>
|
||||
</extension>
|
||||
<module name="compiler-tests-java8" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="9-ea" />
|
||||
<option name="PACKAGE_NAME" value="org.jetbrains.kotlin" />
|
||||
<option name="MAIN_CLASS_NAME" value="" />
|
||||
<option name="METHOD_NAME" value="" />
|
||||
<option name="TEST_OBJECT" value="package" />
|
||||
<option name="VM_PARAMETERS" value="-ea -XX:+HeapDumpOnOutOfMemoryError -XX:+UseCodeCacheFlushing -XX:ReservedCodeCacheSize=64m -Djna.nosys=true --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.desktop/javax.swing=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens java.base/jdk.internal.misc=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED" />
|
||||
<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="singleModule" />
|
||||
</option>
|
||||
<envs />
|
||||
<patterns />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
||||
611
ChangeLog.md
611
ChangeLog.md
@@ -3,599 +3,6 @@
|
||||
<!-- Find: ([^\`/\[])(KT-\d+) -->
|
||||
<!-- Replace: $1[`$2`](https://youtrack.jetbrains.com/issue/$2) -->
|
||||
|
||||
## 1.1
|
||||
|
||||
### Compiler exceptions
|
||||
- [`KT-16411`](https://youtrack.jetbrains.com/issue/KT-16411) Exception from compiler when try to inline callable reference to class constructor inside object
|
||||
- [`KT-16412`](https://youtrack.jetbrains.com/issue/KT-16412) Exception from compiler when try call SAM constructor where argument is callable reference to nested class inside object
|
||||
- [`KT-16413`](https://youtrack.jetbrains.com/issue/KT-16413) When we create sam adapter for java.util.function.Function we add incorrect null-check for argument
|
||||
|
||||
### Standard library
|
||||
- [`KT-6561`](https://youtrack.jetbrains.com/issue/KT-6561) Drop java.util.Collections package from js stdlib
|
||||
|
||||
### IDE
|
||||
- [`KT-16329`](https://youtrack.jetbrains.com/issue/KT-16329) Inspection "Calls to staic methods in Java interfaces..." always reports warning undependent of jvm-target
|
||||
|
||||
|
||||
## 1.1-RC
|
||||
|
||||
### Reflection
|
||||
- [`KT-16358`](https://youtrack.jetbrains.com/issue/KT-16358) Incompatibility between kotlin-reflect 1.0 and kotlin-stdlib 1.1 fixed
|
||||
|
||||
### Compiler
|
||||
|
||||
#### Coroutine support
|
||||
- [`KT-15938`](https://youtrack.jetbrains.com/issue/KT-15938) Changed error message for calling suspend function outside of suspendable context
|
||||
- [`KT-16092`](https://youtrack.jetbrains.com/issue/KT-16092) Backend crash fixed: "Don't know how to generate outer expression" for destructuring suspend lambda
|
||||
- [`KT-16093`](https://youtrack.jetbrains.com/issue/KT-16093) Annotations are retained during reading the binary representation of suspend functions
|
||||
- [`KT-16122`](https://youtrack.jetbrains.com/issue/KT-16122) java.lang.VerifyError fixed in couroutines: (String, null, suspend () -> String)
|
||||
- [`KT-16124`](https://youtrack.jetbrains.com/issue/KT-16124) Marked as UNSUPPORTED: suspension points in default parameters
|
||||
- [`KT-16219`](https://youtrack.jetbrains.com/issue/KT-16219) Marked as UNSUPPORTED: suspend get/set, in/!in operators for
|
||||
- [`KT-16145`](https://youtrack.jetbrains.com/issue/KT-16145) Beta-2 coroutine regression fixed (wrong code generation)
|
||||
|
||||
#### Kapt3
|
||||
- [`KT-15524`](https://youtrack.jetbrains.com/issue/KT-15524) Fix javac error reporting in Kotlin daemon
|
||||
- [`KT-15721`](https://youtrack.jetbrains.com/issue/KT-15721) JetBrains nullability annotations are now returned from Element.getAnnotationMirrors()
|
||||
- [`KT-16146`](https://youtrack.jetbrains.com/issue/KT-16146) Fixed work in verbose mode
|
||||
- [`KT-16153`](https://youtrack.jetbrains.com/issue/KT-16153) Ignore declarations with illegal Java identifiers
|
||||
- [`KT-16167`](https://youtrack.jetbrains.com/issue/KT-16167) Fixed compilation error with kapt arguments in build.gradle
|
||||
- [`KT-16170`](https://youtrack.jetbrains.com/issue/KT-16170) Stub generator now adds imports for corrected error types to stubs
|
||||
- [`KT-16176`](https://youtrack.jetbrains.com/issue/KT-16176) javac's finalCompiler log is now used to determine annotation processing errors
|
||||
|
||||
#### Backward compatibility
|
||||
- [`KT-16017`](https://youtrack.jetbrains.com/issue/KT-16017) More graceful error message for disabled features
|
||||
- [`KT-16073`](https://youtrack.jetbrains.com/issue/KT-16073) Improved backward compatibility mode with version 1.0 on JDK dependent built-ins
|
||||
- [`KT-16094`](https://youtrack.jetbrains.com/issue/KT-16094) Compiler considers API availability when compiling language features requiring runtime support
|
||||
- [`KT-16171`](https://youtrack.jetbrains.com/issue/KT-16171) Fixed regression "Unexpected container error on Kotlin 1.0 project"
|
||||
- [`KT-16199`](https://youtrack.jetbrains.com/issue/KT-16199) Do not import "kotlin.comparisons.*" by default in language version 1.0 mode
|
||||
|
||||
#### Various issues
|
||||
- [`KT-16225`](https://youtrack.jetbrains.com/issue/KT-16225) enumValues non-reified stub implementation references nonexistent method no more
|
||||
- [`KT-16291`](https://youtrack.jetbrains.com/issue/KT-16291) Smart cast works now when getting class of instance
|
||||
- [`KT-16380`](https://youtrack.jetbrains.com/issue/KT-16380) Show warning when running the compiler under Java 6 or 7
|
||||
|
||||
### JavaScript backend
|
||||
- [`KT-16144`](https://youtrack.jetbrains.com/issue/KT-16144) Fixed inlining of functions called through inheritor ("fake" override) from another module
|
||||
- [`KT-16158`](https://youtrack.jetbrains.com/issue/KT-16158) Error is not reported now when library path contains JAR file without JS metadata, report warning instead
|
||||
- [`KT-16160`](https://youtrack.jetbrains.com/issue/KT-16160) Companion object dispatch receiver translation fixed
|
||||
|
||||
### Standard library
|
||||
- [`KT-7858`](https://youtrack.jetbrains.com/issue/KT-7858) Add extension function `takeUnless`
|
||||
- `javaClass` extension property is deprecated, use `instance::class.java` instead
|
||||
- Massive deprecations are coming in JS standard library in `kotlin.dom` and `kotlin.dom.build` packages
|
||||
|
||||
### IDE
|
||||
|
||||
#### Configuration issues
|
||||
- [`KT-15899`](https://youtrack.jetbrains.com/issue/KT-15899) Kotlin facet: language and api version for submodule setup for 1.0 are filled now as 1.0 too
|
||||
- [`KT-15914`](https://youtrack.jetbrains.com/issue/KT-15914) Kotlin facet works now with multi-selected modules in Project Settings too
|
||||
- [`KT-15954`](https://youtrack.jetbrains.com/issue/KT-15954) Does not suggest to configure kotlin for the module after each new kt-file creation
|
||||
- [`KT-16157`](https://youtrack.jetbrains.com/issue/KT-16157) freeCompilerArgs are now imported from Gradle into IDEA
|
||||
- [`KT-16206`](https://youtrack.jetbrains.com/issue/KT-16206) Idea no more refuses to compile a kotlin project defined as a maven project
|
||||
- [`KT-16312`](https://youtrack.jetbrains.com/issue/KT-16312) Kotlin facet: import from gradle: don't import options which are set implicitly already
|
||||
- [`KT-16325`](https://youtrack.jetbrains.com/issue/KT-16325) Kotlin facet: correct configuration after upgrading the IDE plugin
|
||||
- [`KT-16345`](https://youtrack.jetbrains.com/issue/KT-16345) Kotlin facet: detect JavaScript if the module has language 1.0 `kotlin-js-library` dependency
|
||||
|
||||
#### Coroutine support
|
||||
- [`KT-16109`](https://youtrack.jetbrains.com/issue/KT-16109) Error fixed: The -Xcoroutines can only have one value
|
||||
- [`KT-16251`](https://youtrack.jetbrains.com/issue/KT-16251) Fix detection of suspend calls containing extracted parameters
|
||||
|
||||
#### Intention actions, inspections and quick-fixes
|
||||
|
||||
##### 2017.1 compatibility
|
||||
- [`KT-15870`](https://youtrack.jetbrains.com/issue/KT-15870) "Package name does not match containing directory" inspection: fixed throwable "AWT events are not allowed inside write action"
|
||||
- [`KT-15924`](https://youtrack.jetbrains.com/issue/KT-15924) Create Test action: fixed throwable "AWT events are not allowed inside write action"
|
||||
|
||||
##### Bug fixes
|
||||
- [`KT-14831`](https://youtrack.jetbrains.com/issue/KT-14831) Import statement and FQN are not added on converting lambda to reference for typealias
|
||||
- [`KT-15545`](https://youtrack.jetbrains.com/issue/KT-15545) Inspection "join with assignment" does not change now execution order for properties
|
||||
- [`KT-15744`](https://youtrack.jetbrains.com/issue/KT-15744) Fix: intention to import `sleep` wrongly suggests `Thread.sleep`
|
||||
- [`KT-16000`](https://youtrack.jetbrains.com/issue/KT-16000) Inspection "join with assignment" handles initialization with 'this' correctly
|
||||
- [`KT-16009`](https://youtrack.jetbrains.com/issue/KT-16009) Auto-import for JDK classes in .kts files
|
||||
- [`KT-16104`](https://youtrack.jetbrains.com/issue/KT-16104) Don't insert modifiers (e.g. suspend) before visibility
|
||||
|
||||
#### Completion
|
||||
- [`KT-16076`](https://youtrack.jetbrains.com/issue/KT-16076) Completion does not insert more FQN kotlin.text.String
|
||||
- [`KT-16088`](https://youtrack.jetbrains.com/issue/KT-16088) Completion does not insert more FQN for `kotlin` package
|
||||
- [`KT-16110`](https://youtrack.jetbrains.com/issue/KT-16110) Keyword 'suspend' completion inside generic arguments
|
||||
- [`KT-16243`](https://youtrack.jetbrains.com/issue/KT-16243) Performance enhanced after variable of type `ArrayList`
|
||||
|
||||
#### Various issues
|
||||
- [`KT-15291`](https://youtrack.jetbrains.com/issue/KT-15291) 'Find usages' now does not report property access as usage of getter method in Java class with parameter
|
||||
- [`KT-15647`](https://youtrack.jetbrains.com/issue/KT-15647) Exception fixed: KDoc link to member of class from different package and module
|
||||
- [`KT-16071`](https://youtrack.jetbrains.com/issue/KT-16071) IDEA deadlock fixed: when typing "parse()" in .kt file
|
||||
- [`KT-16149`](https://youtrack.jetbrains.com/issue/KT-16149) Intellij Idea 2017.1/Android Studio 2.3 beta3 and Kotlin plugin 1.1-beta2 deadlock fixed
|
||||
|
||||
### Coroutine libraries
|
||||
- [`KT-15716`](https://youtrack.jetbrains.com/issue/KT-15716) Introduced startCoroutineUninterceptedOrReturn coroutine intrinsic
|
||||
- [`KT-15718`](https://youtrack.jetbrains.com/issue/KT-15718) createCoroutine now returns safe continuation
|
||||
- [`KT-16155`](https://youtrack.jetbrains.com/issue/KT-16155) Introduced createCoroutineUnchecked intrinsic
|
||||
|
||||
|
||||
### Gradle support
|
||||
- [`KT-15829`](https://youtrack.jetbrains.com/issue/KT-15829) Gradle Kotlin JS plugin: removed false "Duplicate source root:" warning for kotlin files
|
||||
- [`KT-15902`](https://youtrack.jetbrains.com/issue/KT-15902) JS: gradle task output is now considered as source set output
|
||||
- [`KT-16174`](https://youtrack.jetbrains.com/issue/KT-16174) Error fixed during IDEA-Gradle synchronization for Kotlin JS
|
||||
- [`KT-16267`](https://youtrack.jetbrains.com/issue/KT-16267) JS: fixed regression in 1.1-beta2 for multi-module gradle project
|
||||
- [`KT-16274`](https://youtrack.jetbrains.com/issue/KT-16274) Kotlin JS Gradle unexpected compiler error / absolute path to output file
|
||||
- [`KT-16322`](https://youtrack.jetbrains.com/issue/KT-16322) Circlet project Gradle import issue fixed
|
||||
|
||||
### REPL
|
||||
- [`KT-15861`](https://youtrack.jetbrains.com/issue/KT-15861) Use windows line separator in kotlin's JSR implementation
|
||||
- [`KT-16126`](https://youtrack.jetbrains.com/issue/KT-16126) Proper `jvmTarget` for REPL compilation
|
||||
|
||||
|
||||
## 1.1-Beta2
|
||||
|
||||
### Language related changes
|
||||
- [`KT-7897`](https://youtrack.jetbrains.com/issue/KT-7897) Do not require to call enum constructor for each entry if all parameters have default values
|
||||
- [`KT-8985`](https://youtrack.jetbrains.com/issue/KT-8985) Support T::class.java for T with no non-null upper bound
|
||||
- [`KT-10711`](https://youtrack.jetbrains.com/issue/KT-10711) Type inference works now on generics for callable references
|
||||
- [`KT-13130`](https://youtrack.jetbrains.com/issue/KT-13130) Support exhaustive when for sealed trees
|
||||
- [`KT-15898`](https://youtrack.jetbrains.com/issue/KT-15898) Cannot use type alias to qualify enum entry
|
||||
- [`KT-16061`](https://youtrack.jetbrains.com/issue/KT-16061) Smart type inference on callable references in 1.1 mode only
|
||||
|
||||
### Reflection
|
||||
- [`KT-8384`](https://youtrack.jetbrains.com/issue/KT-8384) Access to the delegate object for a KProperty
|
||||
|
||||
### Compiler
|
||||
|
||||
#### Coroutine support
|
||||
- [`KT-15016`](https://youtrack.jetbrains.com/issue/KT-15016) VerifyError with coroutine: fix processing of uninitialized instances
|
||||
- [`KT-15527`](https://youtrack.jetbrains.com/issue/KT-15527) Coroutine compile error: wrong code generated for safe qualified suspension points
|
||||
- [`KT-15552`](https://youtrack.jetbrains.com/issue/KT-15552) Accessor implementation of suspended function produces AbstractMethodError
|
||||
- [`KT-15715`](https://youtrack.jetbrains.com/issue/KT-15715) Coroutine generate invalid invoke
|
||||
- [`KT-15820`](https://youtrack.jetbrains.com/issue/KT-15820) Coroutine Internal Error regression with dispatcher + this@
|
||||
- [`KT-15821`](https://youtrack.jetbrains.com/issue/KT-15821) Coroutine internal error regression: Could not inline method call apply
|
||||
- [`KT-15824`](https://youtrack.jetbrains.com/issue/KT-15824) Coroutine iterator regression: Object cannot be cast to java.lang.Boolean
|
||||
- [`KT-15827`](https://youtrack.jetbrains.com/issue/KT-15827) Show Kotlin Bytecode shows wrong bytecode for suspending functions
|
||||
- [`KT-15907`](https://youtrack.jetbrains.com/issue/KT-15907) Bogus error about platform declaration clash with private suspend functions
|
||||
- [`KT-15933`](https://youtrack.jetbrains.com/issue/KT-15933) Suspend getValue/setValue/provideDelegate do not work properly
|
||||
- [`KT-15935`](https://youtrack.jetbrains.com/issue/KT-15935) Private suspend function in file causes UnsupportedOperationException: Context does not have a "this"
|
||||
- [`KT-15963`](https://youtrack.jetbrains.com/issue/KT-15963) Coroutine: runtime error if returned object "equals" does not like comparison to SUSPENDED_MARKER
|
||||
- [`KT-16068`](https://youtrack.jetbrains.com/issue/KT-16068) Prohibit inline lambda parameters of suspend function type
|
||||
|
||||
#### Diagnostics
|
||||
- [`KT-1560`](https://youtrack.jetbrains.com/issue/KT-1560) Report diagnostic for a declaration of extension function which will be always shadowed by member function
|
||||
- [`KT-12846`](https://youtrack.jetbrains.com/issue/KT-12846) Forbid vararg of Nothing
|
||||
- [`KT-13227`](https://youtrack.jetbrains.com/issue/KT-13227) NO_ELSE_IN_WHEN in when by sealed class instance if is-check for base sealed class is used
|
||||
- [`KT-13355`](https://youtrack.jetbrains.com/issue/KT-13355) Type mismatch on inheritance is not reported on abstract class
|
||||
- [`KT-15010`](https://youtrack.jetbrains.com/issue/KT-15010) Missing error on an usage of non-constant property in annotation default argument
|
||||
- [`KT-15201`](https://youtrack.jetbrains.com/issue/KT-15201) Compiler is complaining about when statement without null condition even if null is checked before.
|
||||
- [`KT-15736`](https://youtrack.jetbrains.com/issue/KT-15736) Report an error on type alias expanded to a nullable type on LHS of a class literal
|
||||
- [`KT-15740`](https://youtrack.jetbrains.com/issue/KT-15740) Report error on expression of a nullable type on LHS of a class literal
|
||||
- [`KT-15844`](https://youtrack.jetbrains.com/issue/KT-15844) Do not allow to access primary constructor parameters from property with custom getter
|
||||
- [`KT-15878`](https://youtrack.jetbrains.com/issue/KT-15878) Extension shadowed by member should not be reported for infix/operator extensions when member is non-infix/operator
|
||||
- [`KT-16010`](https://youtrack.jetbrains.com/issue/KT-16010) Do not highlight lambda parameters as unused in 1.0 compatibility mode
|
||||
|
||||
#### Kapt
|
||||
- [`KT-15675`](https://youtrack.jetbrains.com/issue/KT-15675) Kapt3 does not generate classes annotated with AutoValue
|
||||
- [`KT-15697`](https://youtrack.jetbrains.com/issue/KT-15697) If an annotation with AnnotationTarget.PROPERTY is tagged on a Kotlin property, it breaks annotation processing
|
||||
- [`KT-15803`](https://youtrack.jetbrains.com/issue/KT-15803) Kotlin 1.0.6 broke Dagger
|
||||
- [`KT-15814`](https://youtrack.jetbrains.com/issue/KT-15814) Regression: Kapt is not working in 1.0.6 / 1.1-M04 / 1.1-Beta
|
||||
- [`KT-15838`](https://youtrack.jetbrains.com/issue/KT-15838) kapt3 1.1-beta: KaptError: Java file parsing error
|
||||
- [`KT-15841`](https://youtrack.jetbrains.com/issue/KT-15841) 1.1-Beta + kapt3 fails to build the project with StackOverflowError
|
||||
- [`KT-15915`](https://youtrack.jetbrains.com/issue/KT-15915) Kapt: Kotlin class target directory is cleared before compilation (and after kapt task)
|
||||
- [`KT-16006`](https://youtrack.jetbrains.com/issue/KT-16006) Cannot determine if type is an error type during annotation processing
|
||||
|
||||
#### Exceptions / Errors
|
||||
- [`KT-8264`](https://youtrack.jetbrains.com/issue/KT-8264) Internal compiler error: java.lang.ArithmeticException: BigInteger: modulus not positive
|
||||
- [`KT-14547`](https://youtrack.jetbrains.com/issue/KT-14547) NoSuchElementException when compiling callable reference without stdlib in the classpath
|
||||
- [`KT-14966`](https://youtrack.jetbrains.com/issue/KT-14966) Regression: VerifyError on access super implementation from delegate
|
||||
- [`KT-15017`](https://youtrack.jetbrains.com/issue/KT-15017) Throwing exception in the end of inline suspend-functions lead to internal compiler error
|
||||
- [`KT-15439`](https://youtrack.jetbrains.com/issue/KT-15439) Resolved call is not completed for generic callable reference in if-expression
|
||||
- [`KT-15500`](https://youtrack.jetbrains.com/issue/KT-15500) Exception passing freeCompilerArgs to gradle plugin
|
||||
- [`KT-15646`](https://youtrack.jetbrains.com/issue/KT-15646) InconsistentDebugInfoException when stepping over `throw`
|
||||
- [`KT-15726`](https://youtrack.jetbrains.com/issue/KT-15726) Kotlin compiles invalid bytecode for nested try-catch with return
|
||||
- [`KT-15743`](https://youtrack.jetbrains.com/issue/KT-15743) Overloaded Kotlin extensions annotates wrong parameters in java
|
||||
- [`KT-15868`](https://youtrack.jetbrains.com/issue/KT-15868) NPE when comparing nullable doubles for equality
|
||||
- [`KT-15995`](https://youtrack.jetbrains.com/issue/KT-15995) Can't build project with DataBinding using Kotlin 1.1: incompatible language version
|
||||
- [`KT-16047`](https://youtrack.jetbrains.com/issue/KT-16047) Internal Error: org.jetbrains.kotlin.util.KotlinFrontEndException while analyzing expression
|
||||
|
||||
#### Type inference issues
|
||||
- [`KT-10268`](https://youtrack.jetbrains.com/issue/KT-10268) Wrong type inference related to captured types
|
||||
- [`KT-11259`](https://youtrack.jetbrains.com/issue/KT-11259) Wrong type inference for Java 8 Stream.collect.
|
||||
- [`KT-12802`](https://youtrack.jetbrains.com/issue/KT-12802) Type inference failed when irrelevant method reference is used
|
||||
- [`KT-12964`](https://youtrack.jetbrains.com/issue/KT-12964) Support type inference for callable references from parameter types of an expected function type
|
||||
|
||||
#### Smart cast issues
|
||||
- [`KT-13468`](https://youtrack.jetbrains.com/issue/KT-13468) Smart cast is broken after assignment of 'if' expression
|
||||
- [`KT-14350`](https://youtrack.jetbrains.com/issue/KT-14350) Make smart-cast work as it does in 1.0 when -language-version 1.0 is used
|
||||
- [`KT-14597`](https://youtrack.jetbrains.com/issue/KT-14597) When over smartcast enum is broken and breaks all other "when"
|
||||
- [`KT-15792`](https://youtrack.jetbrains.com/issue/KT-15792) Wrong smart cast after y = x, x = null, y != null sequence
|
||||
|
||||
#### Various issues
|
||||
- [`KT-15236`](https://youtrack.jetbrains.com/issue/KT-15236) False positive: Null can not be a value of a non-null type
|
||||
- [`KT-15677`](https://youtrack.jetbrains.com/issue/KT-15677) Modifiers and annotations are lost on a (nullable) parenthesized type
|
||||
- [`KT-15707`](https://youtrack.jetbrains.com/issue/KT-15707) IDEA unable to parallel compile different projects
|
||||
- [`KT-15734`](https://youtrack.jetbrains.com/issue/KT-15734) Nullability is lost during expansion of a type alias
|
||||
- [`KT-15748`](https://youtrack.jetbrains.com/issue/KT-15748) Type alias constructor return type should have a corresponding abbreviation
|
||||
- [`KT-15775`](https://youtrack.jetbrains.com/issue/KT-15775) Annotations are lost on value parameter types of a function type
|
||||
- [`KT-15780`](https://youtrack.jetbrains.com/issue/KT-15780) Treat Map.getOrDefault overrides in Java the same way as in 1.0.x compiler with language version 1.0
|
||||
- [`KT-15794`](https://youtrack.jetbrains.com/issue/KT-15794) Refine backward compatibility mode for additional built-ins members from JDK
|
||||
- [`KT-15848`](https://youtrack.jetbrains.com/issue/KT-15848) Implement additional annotation processing in the `KotlinScriptDefinitionFromAnnotatedTemplate` for SamWithReceiver plugin
|
||||
- [`KT-15875`](https://youtrack.jetbrains.com/issue/KT-15875) Operation has lead to overflow for 'mod' with negative first operand
|
||||
- [`KT-15945`](https://youtrack.jetbrains.com/issue/KT-15945) Feature Request: Andrey Breslav to grow a beard.
|
||||
|
||||
### JavaScript backend
|
||||
|
||||
#### Coroutine support
|
||||
- [`KT-15834`](https://youtrack.jetbrains.com/issue/KT-15834) JS: Local delegate in suspend function
|
||||
- [`KT-15892`](https://youtrack.jetbrains.com/issue/KT-15892) JS: safe call of suspend functions causes compiler to crash
|
||||
|
||||
#### Diagnostics
|
||||
- [`KT-14668`](https://youtrack.jetbrains.com/issue/KT-14668) Do not allow declarations in 'kotlin' package or subpackages in JS
|
||||
- [`KT-15184`](https://youtrack.jetbrains.com/issue/KT-15184) JS: prohibit `..` operation with `dynamic` on left-hand side
|
||||
- [`KT-15253`](https://youtrack.jetbrains.com/issue/KT-15253) JS: no error when use class external class with JsModule in type context when compiling with plain module kind
|
||||
- [`KT-15283`](https://youtrack.jetbrains.com/issue/KT-15283) JS: additional restrictions on dynamic
|
||||
- [`KT-15961`](https://youtrack.jetbrains.com/issue/KT-15961) Could not implement external open class with function with optional parameter
|
||||
|
||||
#### Language feature support
|
||||
- [`KT-14035`](https://youtrack.jetbrains.com/issue/KT-14035) JS: support implementing CharSequence
|
||||
- [`KT-14036`](https://youtrack.jetbrains.com/issue/KT-14036) JS: use Int16 for Char when it possible and box to our Char otherwise
|
||||
- [`KT-14097`](https://youtrack.jetbrains.com/issue/KT-14097) Wrong code generated for enum entry initialization using non-primary no-argument constructor
|
||||
- [`KT-15312`](https://youtrack.jetbrains.com/issue/KT-15312) JS: map kotlin.Throwable to JS Error
|
||||
- [`KT-15765`](https://youtrack.jetbrains.com/issue/KT-15765) JS: support callable references on built-in and intrinsic functions and properties
|
||||
- [`KT-15900`](https://youtrack.jetbrains.com/issue/KT-15900) JS: Support enum entry with empty initializer with vararg constructor
|
||||
|
||||
#### Standard library support
|
||||
- [`KT-4141`](https://youtrack.jetbrains.com/issue/KT-4141) JS: wrong return type for Date::getTime
|
||||
- [`KT-4497`](https://youtrack.jetbrains.com/issue/KT-4497) JS: add String.toInt, String.toDouble etc extension functions, `parseInt` and `parseFloat` are deprecated in favor of these new ones
|
||||
- [`KT-15940`](https://youtrack.jetbrains.com/issue/KT-15940) JS: rename all js standard library artifacts (both in maven and in compiler distribution) to `kotlin-stdlib-js.jar`
|
||||
- Add `Promise<T>` external declaration to the standard library
|
||||
- Types like `Date`, `Math`, `Console`, `Promise`, `RegExp`, `Json` require explicit import from `kotlin.js` package
|
||||
|
||||
#### External declarations
|
||||
- [`KT-15144`](https://youtrack.jetbrains.com/issue/KT-15144) JS: rename `noImpl` to `definedExternally`
|
||||
- [`KT-15306`](https://youtrack.jetbrains.com/issue/KT-15306) JS: allow to use `definedExternally` only inside a body of external declarations
|
||||
- [`KT-15336`](https://youtrack.jetbrains.com/issue/KT-15336) JS: allow to inherit external classes from kotlin.Throwable
|
||||
- [`KT-15905`](https://youtrack.jetbrains.com/issue/KT-15905) JS: add a way to control qualifier for external declarations inside file
|
||||
- Deprecate `@native` annotation, to be removed in 1.1 release.
|
||||
|
||||
#### Exceptions / Errors
|
||||
- [`KT-10894`](https://youtrack.jetbrains.com/issue/KT-10894) Infinite indexing at projects with JS modules
|
||||
- [`KT-14124`](https://youtrack.jetbrains.com/issue/KT-14124) AssertionError: strings file not found on K2JS serialized data
|
||||
|
||||
#### Various issues
|
||||
- [`KT-8211`](https://youtrack.jetbrains.com/issue/KT-8211) JS: generate dummy init for properties w/o initializer to avoid to have different hidden classes for different instances
|
||||
- [`KT-12712`](https://youtrack.jetbrains.com/issue/KT-12712) JS: Json should not be a class
|
||||
- [`KT-13312`](https://youtrack.jetbrains.com/issue/KT-13312) JS: can't use extension lambda where expected lambda and vice versa
|
||||
- [`KT-13632`](https://youtrack.jetbrains.com/issue/KT-13632) Add template kotlin js project under gradle in "New Project" window
|
||||
- [`KT-15278`](https://youtrack.jetbrains.com/issue/KT-15278) JS: don't treat property access through dynamic as side effect free
|
||||
- [`KT-15285`](https://youtrack.jetbrains.com/issue/KT-15285) JS: take into account as many characteristics from the signature as possible when mangling
|
||||
- [`KT-15678`](https://youtrack.jetbrains.com/issue/KT-15678) JS: Generated local variable named 'element' clashes with actual local variable named 'element'
|
||||
- [`KT-15755`](https://youtrack.jetbrains.com/issue/KT-15755) JS compiler produces a lot of empty kotlin_file_table files for irrelevant packages
|
||||
- [`KT-15770`](https://youtrack.jetbrains.com/issue/KT-15770) Name clash between recursive local functions with same name
|
||||
- [`KT-15797`](https://youtrack.jetbrains.com/issue/KT-15797) JS: wrong code for accessing nested class inside js module
|
||||
- [`KT-15863`](https://youtrack.jetbrains.com/issue/KT-15863) JS: Extension function reference shifts parameters loosing the receiver
|
||||
- [`KT-16049`](https://youtrack.jetbrains.com/issue/KT-16049) JS: drop "-kjsm" command line option, merge the logic into "-meta-info"
|
||||
- [`KT-16083`](https://youtrack.jetbrains.com/issue/KT-16083) JS: rename "-library-files" argument to "-libraries" and change separator from comma to system file separator
|
||||
|
||||
### Standard Library
|
||||
- [`KT-13353`](https://youtrack.jetbrains.com/issue/KT-13353) Add Map.minus(key) and Map.minus(keys)
|
||||
- [`KT-13826`](https://youtrack.jetbrains.com/issue/KT-13826) Add parameter names in function types used in the standard library
|
||||
- [`KT-14279`](https://youtrack.jetbrains.com/issue/KT-14279) Make String.matches(Regex) and Regex.matches(String) infix
|
||||
- [`KT-15399`](https://youtrack.jetbrains.com/issue/KT-15399) Iterable.average() now returns NaN for an empty collection
|
||||
- [`KT-15975`](https://youtrack.jetbrains.com/issue/KT-15975) Move coroutine-related runtime parts to `kotlin.coroutines.experimental` package
|
||||
- [`KT-16030`](https://youtrack.jetbrains.com/issue/KT-16030) Move bitwise operations on Byte and Short to `kotlin.experimental` package
|
||||
- [`KT-16026`](https://youtrack.jetbrains.com/issue/KT-16026) Classes compiled in 1.1 in 1.0-compatibility mode may contain references to CloseableKt class from 1.1
|
||||
|
||||
### IDE
|
||||
|
||||
#### Configuration issues
|
||||
- [`KT-15621`](https://youtrack.jetbrains.com/issue/KT-15621) Copy compiler options values from project settings on creating a kotlin facet for Kotlin (JVM) project
|
||||
- [`KT-15623`](https://youtrack.jetbrains.com/issue/KT-15623) Copy compiler options values from project settings on creating a kotlin facet for Kotlin (JavaScript) project
|
||||
- [`KT-15624`](https://youtrack.jetbrains.com/issue/KT-15624) Set option "Use project settings" in newly created Kotlin facet
|
||||
- [`KT-15712`](https://youtrack.jetbrains.com/issue/KT-15712) Configuring a project with Maven or Gradle should automatically use stdlib-jre7 or stdlib-jre8 instead of standard stdlib
|
||||
- [`KT-15772`](https://youtrack.jetbrains.com/issue/KT-15772) Facet does not pick up api version from maven
|
||||
- [`KT-15819`](https://youtrack.jetbrains.com/issue/KT-15819) It would be nice if compileKotlin options are imported into Kotlin facet from gradle/maven
|
||||
- [`KT-16015`](https://youtrack.jetbrains.com/issue/KT-16015) Prohibit api-version > language-version in Facet and Project Settings
|
||||
|
||||
#### Coroutine support
|
||||
- [`KT-14704`](https://youtrack.jetbrains.com/issue/KT-14704) Extract Method should work in coroutines
|
||||
- [`KT-15955`](https://youtrack.jetbrains.com/issue/KT-15955) Quick-fix to enable coroutines through Gradle project configuration
|
||||
- [`KT-16018`](https://youtrack.jetbrains.com/issue/KT-16018) Hide coroutines intrinsics from import and completion
|
||||
- [`KT-16075`](https://youtrack.jetbrains.com/issue/KT-16075) Error:Kotlin: The -Xcoroutines can only have one value
|
||||
|
||||
#### Backward compatibility issues
|
||||
- [`KT-15134`](https://youtrack.jetbrains.com/issue/KT-15134) Do not suggest using destructuring lambda if this will result in "available since 1.1" error
|
||||
- [`KT-15918`](https://youtrack.jetbrains.com/issue/KT-15918) Quick fix "Set module language level to 1.1" should also set API version to 1.1
|
||||
- [`KT-15969`](https://youtrack.jetbrains.com/issue/KT-15969) Replace operator with function should use either rem or mod for % depending on language version
|
||||
- [`KT-15978`](https://youtrack.jetbrains.com/issue/KT-15978) Type alias from Kotlin 1.1 are suggested in completion even if language level is set to 1.0 in settings
|
||||
- [`KT-15979`](https://youtrack.jetbrains.com/issue/KT-15979) Usages of type aliases are not shown as errors in editor if language version is set to 1.0
|
||||
- [`KT-16019`](https://youtrack.jetbrains.com/issue/KT-16019) Do not suggest renaming to underscore in 1.0 compatibility mode
|
||||
- [`KT-16036`](https://youtrack.jetbrains.com/issue/KT-16036) "Create type alias from usage" quick-fix should not be suggested at language level 1.0
|
||||
|
||||
#### Intention actions, inspections and quick-fixes
|
||||
|
||||
##### New features
|
||||
- [`KT-9912`](https://youtrack.jetbrains.com/issue/KT-9912) Merge ifs intention
|
||||
- [`KT-13427`](https://youtrack.jetbrains.com/issue/KT-13427) "Specify type explicitly" should support type aliases
|
||||
- [`KT-15066`](https://youtrack.jetbrains.com/issue/KT-15066) "Make private/.." intention on type aliases
|
||||
- [`KT-15709`](https://youtrack.jetbrains.com/issue/KT-15709) Add inspection for private primary constructors in data classes as they are accessible via the copy method
|
||||
- [`KT-15738`](https://youtrack.jetbrains.com/issue/KT-15738) Intention to add `suspend` modifier to functional type
|
||||
- [`KT-15800`](https://youtrack.jetbrains.com/issue/KT-15800) Quick-fix to convert a function to suspending on error when calling suspension inside
|
||||
|
||||
##### Bug fixes
|
||||
- [`KT-13710`](https://youtrack.jetbrains.com/issue/KT-13710) Import intention action should not appear in import list
|
||||
- [`KT-14680`](https://youtrack.jetbrains.com/issue/KT-14680) import statement to type alias reported as unused when using only TA constructor
|
||||
- [`KT-14856`](https://youtrack.jetbrains.com/issue/KT-14856) TextView internationalisation intention does not report the problem
|
||||
- [`KT-14993`](https://youtrack.jetbrains.com/issue/KT-14993) Keep destructuring declaration parameter on inspection "Remove explicit lambda parameter types"
|
||||
- [`KT-14994`](https://youtrack.jetbrains.com/issue/KT-14994) PsiInvalidElementAccessException and incorrect generation on inspection "Specify type explicitly" on destructuring parameter
|
||||
- [`KT-15162`](https://youtrack.jetbrains.com/issue/KT-15162) "Remove explicit lambda parameter types" intentions fails with destructuring declaration with KNPE at KtPsiFactory.createLambdaParameterList()
|
||||
- [`KT-15311`](https://youtrack.jetbrains.com/issue/KT-15311) "Add Import" intention generates incorrect code
|
||||
- [`KT-15406`](https://youtrack.jetbrains.com/issue/KT-15406) Convert to secondary constructor for enum class should put new members after enum values
|
||||
- [`KT-15553`](https://youtrack.jetbrains.com/issue/KT-15553) Copy concatenation text to clipboard with Kotlin and string interpolation does not work
|
||||
- [`KT-15670`](https://youtrack.jetbrains.com/issue/KT-15670) 'Convert to lambda' quick fix in IDEA leaves single-line comment and } gets commented out
|
||||
- [`KT-15873`](https://youtrack.jetbrains.com/issue/KT-15873) Alt+Enter menu isn't shown for deprecated mod function
|
||||
- [`KT-15874`](https://youtrack.jetbrains.com/issue/KT-15874) Replace operator with function call replaces % with deprecated mod
|
||||
- [`KT-15884`](https://youtrack.jetbrains.com/issue/KT-15884) False positive "Redundant .let call"
|
||||
- [`KT-16072`](https://youtrack.jetbrains.com/issue/KT-16072) Intentions to convert suspend lambdas to callable references should not be shown
|
||||
|
||||
#### Android support
|
||||
- [`KT-13275`](https://youtrack.jetbrains.com/issue/KT-13275) Kotlin Gradle plugin for Android does not work when jackOptions enabled
|
||||
- [`KT-15150`](https://youtrack.jetbrains.com/issue/KT-15150) Android: Add quick-fix to generate View constructor convention
|
||||
- [`KT-15282`](https://youtrack.jetbrains.com/issue/KT-15282) Issues debugging crossinline Android code
|
||||
|
||||
#### KDoc
|
||||
- [`KT-14710`](https://youtrack.jetbrains.com/issue/KT-14710) Sample references are not resolved in IDE
|
||||
- [`KT-15796`](https://youtrack.jetbrains.com/issue/KT-15796) Import of class referenced only in KDoc not preserved after copy-paste
|
||||
|
||||
#### Various issues
|
||||
- [`KT-9011`](https://youtrack.jetbrains.com/issue/KT-9011) Shift+Enter should insert curly braces when invoked after class declaration
|
||||
- [`KT-11308`](https://youtrack.jetbrains.com/issue/KT-11308) Hide kotlin.jvm.internal package contents from completion and auto-import
|
||||
- [`KT-14252`](https://youtrack.jetbrains.com/issue/KT-14252) Completion could suggest constructors available via type aliases
|
||||
- [`KT-14722`](https://youtrack.jetbrains.com/issue/KT-14722) Completion list isn't filled up for type alias to object
|
||||
- [`KT-14767`](https://youtrack.jetbrains.com/issue/KT-14767) Type alias to annotation class should appear in the completion list
|
||||
- [`KT-14859`](https://youtrack.jetbrains.com/issue/KT-14859) "Parameter Info" sometimes does not work properly inside lambda
|
||||
- [`KT-15032`](https://youtrack.jetbrains.com/issue/KT-15032) Injected fragment: descriptor was not found for declaration: FUN
|
||||
- [`KT-15153`](https://youtrack.jetbrains.com/issue/KT-15153) Support typeAlias extensions in completion and add import
|
||||
- [`KT-15786`](https://youtrack.jetbrains.com/issue/KT-15786) NoSuchMethodError: com.intellij.util.containers.UtilKt.isNullOrEmpty
|
||||
- [`KT-15883`](https://youtrack.jetbrains.com/issue/KT-15883) Generating equals() and hashCode(): hashCode does not correctly honor variable names with back ticks
|
||||
- [`KT-15911`](https://youtrack.jetbrains.com/issue/KT-15911) Kotlin REPL will not launch: "Neither main class nor JAR path is specified"
|
||||
|
||||
### J2K
|
||||
- [`KT-15789`](https://youtrack.jetbrains.com/issue/KT-15789) Kotlin plugin incorrectly converts for-loops from Java to Kotlin
|
||||
|
||||
### Gradle support
|
||||
- [`KT-14830`](https://youtrack.jetbrains.com/issue/KT-14830) Kotlin Gradle plugin configuration should not add 'kotlin' source directory by default
|
||||
- [`KT-15279`](https://youtrack.jetbrains.com/issue/KT-15279) 'Kotlin not configured message' should not be displayed while gradle sync is in progress
|
||||
- [`KT-15812`](https://youtrack.jetbrains.com/issue/KT-15812) Create Kotlin facet on importing gradle project with unchecked option Create separate module per source set
|
||||
- [`KT-15837`](https://youtrack.jetbrains.com/issue/KT-15837) Gradle compiler attempts to connect to daemon on address derived from DNS lookup
|
||||
- [`KT-15909`](https://youtrack.jetbrains.com/issue/KT-15909) Copy Gradle compiler options to facets in Intellij/AS
|
||||
- [`KT-15929`](https://youtrack.jetbrains.com/issue/KT-15929) Gradle project imported with wrong 'target platform'
|
||||
|
||||
### Other issues
|
||||
- [`KT-15450`](https://youtrack.jetbrains.com/issue/KT-15450) JSR 223 - support eval with bindings
|
||||
|
||||
|
||||
## 1.1.0-Beta
|
||||
|
||||
### Reflection
|
||||
- [`KT-15540`](https://youtrack.jetbrains.com/issue/KT-15540) findAnnotation returns T?, but it throws NoSuchElementException when there is no matching annotation
|
||||
- Reflection API in `kotlin-reflect` library is moved to `kotlin.reflect.full` package, declarations in the package `kotlin.reflect` are left deprecated. Please migrate according to the hints provided.
|
||||
|
||||
### Compiler
|
||||
|
||||
#### Coroutine support
|
||||
- [`KT-15379`](https://youtrack.jetbrains.com/issue/KT-15379) Allow invoke on instances of suspend function type inside suspend function
|
||||
- [`KT-15380`](https://youtrack.jetbrains.com/issue/KT-15380) Support suspend function type with value parameters
|
||||
- [`KT-15391`](https://youtrack.jetbrains.com/issue/KT-15391) Prohibit suspend function type in supertype list
|
||||
- [`KT-15392`](https://youtrack.jetbrains.com/issue/KT-15392) Prohibit local suspending function
|
||||
- [`KT-15413`](https://youtrack.jetbrains.com/issue/KT-15413) Override regular functions with suspending ones and vice versa
|
||||
- [`KT-15657`](https://youtrack.jetbrains.com/issue/KT-15657) Refine dispatchResume convention
|
||||
- [`KT-15662`](https://youtrack.jetbrains.com/issue/KT-15662) Prohibit callable references to suspend functions
|
||||
|
||||
#### Diagnostics
|
||||
- [`KT-9630`](https://youtrack.jetbrains.com/issue/KT-9630) Cannot create extension function on intersection of types
|
||||
- [`KT-11398`](https://youtrack.jetbrains.com/issue/KT-11398) Possible false positive for INACCESSIBLE_TYPE
|
||||
- [`KT-13593`](https://youtrack.jetbrains.com/issue/KT-13593) Do not report USELESS_ELVIS_RIGHT_IS_NULL for left argument with platform type
|
||||
- [`KT-13859`](https://youtrack.jetbrains.com/issue/KT-13859) Wrong error about using unrepeatable annotation when mix implicit and explicit targets
|
||||
- [`KT-14179`](https://youtrack.jetbrains.com/issue/KT-14179) Prohibit to use enum entry as type parameter
|
||||
- [`KT-15097`](https://youtrack.jetbrains.com/issue/KT-15097) Inherited platform declarations clash: regression under 1.1 when indirectly inheriting from java.util.Map
|
||||
- [`KT-15287`](https://youtrack.jetbrains.com/issue/KT-15287) Kotlin runtime 1.1 and runtime 1.0.x: Overload resolution ambiguity
|
||||
- [`KT-15334`](https://youtrack.jetbrains.com/issue/KT-15334) Incorrect "val cannot be reassigned" inside do-while
|
||||
- [`KT-15410`](https://youtrack.jetbrains.com/issue/KT-15410) "Protected function call from public-API inline function" for protected constructor call
|
||||
|
||||
#### Kapt3
|
||||
- [`KT-15145`](https://youtrack.jetbrains.com/issue/KT-15145) Kapt3: Doesn't compile with multiple errors
|
||||
- [`KT-15232`](https://youtrack.jetbrains.com/issue/KT-15232) Kapt3 crash due to java codepage
|
||||
- [`KT-15359`](https://youtrack.jetbrains.com/issue/KT-15359) Kapt3 exception while annotation processing (DataBindings AS2.3-beta1)
|
||||
- [`KT-15375`](https://youtrack.jetbrains.com/issue/KT-15375) Kapt3 can't find ${env.JDK_18}/lib/tools.jar
|
||||
- [`KT-15381`](https://youtrack.jetbrains.com/issue/KT-15381) Unresolved references: R with Kapt3
|
||||
- [`KT-15397`](https://youtrack.jetbrains.com/issue/KT-15397) Kapt3 doesn't work with databinding
|
||||
- [`KT-15409`](https://youtrack.jetbrains.com/issue/KT-15409) Kapt3 Cannot find the getter for attribute 'android:text' with value type java.lang.String on android.widget.EditText.
|
||||
- [`KT-15421`](https://youtrack.jetbrains.com/issue/KT-15421) Kapt3: Substitute types from Psi instead of writing NonExistentClass for generated type names
|
||||
- [`KT-15459`](https://youtrack.jetbrains.com/issue/KT-15459) Kapt3 doesn't generate code in test module
|
||||
- [`KT-15524`](https://youtrack.jetbrains.com/issue/KT-15524) Kapt3 - Error messages should display associated element information (if available)
|
||||
- [`KT-15713`](https://youtrack.jetbrains.com/issue/KT-15713) Kapt3: circular dependencies between Gradke tasks
|
||||
|
||||
#### Exceptions / Errors
|
||||
- [`KT-11401`](https://youtrack.jetbrains.com/issue/KT-11401) Error type encountered for implicit invoke with function literal argument
|
||||
- [`KT-12044`](https://youtrack.jetbrains.com/issue/KT-12044) Assertion "Rewrite at slice LEXICAL_SCOPE" for 'if' with property references
|
||||
- [`KT-14011`](https://youtrack.jetbrains.com/issue/KT-14011) Compiler crash when inlining: lateinit property allRecapturedParameters has not been initialized
|
||||
- [`KT-14868`](https://youtrack.jetbrains.com/issue/KT-14868) CCE in runtime while converting Number to Char
|
||||
- [`KT-15364`](https://youtrack.jetbrains.com/issue/KT-15364) VerifyError: Bad type on operand stack on ObserverIterator.hasNext
|
||||
- [`KT-15373`](https://youtrack.jetbrains.com/issue/KT-15373) Internal error when running TestNG test
|
||||
- [`KT-15437`](https://youtrack.jetbrains.com/issue/KT-15437) VerifyError: Bad local variable type on simplest provideDelegate
|
||||
- [`KT-15446`](https://youtrack.jetbrains.com/issue/KT-15446) Property reference on an instance of subclass causes java.lang.VerifyError
|
||||
- [`KT-15447`](https://youtrack.jetbrains.com/issue/KT-15447) Compiler backend error: "Don't know how to generate outer expression for class"
|
||||
- [`KT-15449`](https://youtrack.jetbrains.com/issue/KT-15449) Back-end (JVM) Internal error: Couldn't inline method call
|
||||
- [`KT-15464`](https://youtrack.jetbrains.com/issue/KT-15464) Regression: "Supertypes of the following classes cannot be resolved. Please make sure you have the required dependencies in the classpath:"
|
||||
- [`KT-15575`](https://youtrack.jetbrains.com/issue/KT-15575) VerifyError: Bad type on operand stack
|
||||
|
||||
#### Various issues
|
||||
- [`KT-11962`](https://youtrack.jetbrains.com/issue/KT-11962) Super call with default parameters check is generated for top-level function
|
||||
- [`KT-11969`](https://youtrack.jetbrains.com/issue/KT-11969) ProGuard issue with private interface methods
|
||||
- [`KT-12795`](https://youtrack.jetbrains.com/issue/KT-12795) Write information about sealed class inheritors to metadata
|
||||
- [`KT-13718`](https://youtrack.jetbrains.com/issue/KT-13718) ClassFormatError on aspectj instrumentation
|
||||
- [`KT-14162`](https://youtrack.jetbrains.com/issue/KT-14162) Support @InlineOnly on inline properties
|
||||
- [`KT-14705`](https://youtrack.jetbrains.com/issue/KT-14705) Inconsistent smart casts on when enum subject
|
||||
- [`KT-14917`](https://youtrack.jetbrains.com/issue/KT-14917) No way to pass additional java command line options to kontlinc on Windows
|
||||
- [`KT-15112`](https://youtrack.jetbrains.com/issue/KT-15112) Compiler hangs on nested lock compilation
|
||||
- [`KT-15225`](https://youtrack.jetbrains.com/issue/KT-15225) Scripts: generate classes with names that are valid Java identifiers
|
||||
- [`KT-15411`](https://youtrack.jetbrains.com/issue/KT-15411) Unnecessary CHECKCAST bytecode when dealing with null
|
||||
- [`KT-15473`](https://youtrack.jetbrains.com/issue/KT-15473) Invalid KFunction byte code signature for callable references
|
||||
- [`KT-15582`](https://youtrack.jetbrains.com/issue/KT-15582) Generated bytecode is sometimes incompatible with Java 9
|
||||
- [`KT-15584`](https://youtrack.jetbrains.com/issue/KT-15584) Do not mark class files compiled with a release language version as pre-release
|
||||
- [`KT-15589`](https://youtrack.jetbrains.com/issue/KT-15589) Upper bound for T in KClass<T> can be implicitly violated using generic function
|
||||
- [`KT-15631`](https://youtrack.jetbrains.com/issue/KT-15631) Compiler hang in MethodAnalyzer.analyze() fixed
|
||||
|
||||
### JavaScript backend
|
||||
|
||||
#### Coroutine support
|
||||
- [`KT-15362`](https://youtrack.jetbrains.com/issue/KT-15362) JS: Regex doesn't work (properly) in coroutine
|
||||
- [`KT-15366`](https://youtrack.jetbrains.com/issue/KT-15366) JS: error when calling inline function with optional parameters from another module inside coroutine lambda
|
||||
- [`KT-15367`](https://youtrack.jetbrains.com/issue/KT-15367) JS: `for` against iterator with suspend `next` and `hasNext` functions does not work
|
||||
- [`KT-15400`](https://youtrack.jetbrains.com/issue/KT-15400) suspendCoroutine is missing in JS BE
|
||||
- [`KT-15597`](https://youtrack.jetbrains.com/issue/KT-15597) Support non-tail suspend calls inside named suspend functions
|
||||
- [`KT-15625`](https://youtrack.jetbrains.com/issue/KT-15625) JS: return statement without value surrounded by `try..finally` in suspend lambda causes compiler error
|
||||
- [`KT-15698`](https://youtrack.jetbrains.com/issue/KT-15698) Move coroutine intrinsics to kotlin.coroutine.intrinsics package
|
||||
|
||||
#### Diagnostics
|
||||
- [`KT-14577`](https://youtrack.jetbrains.com/issue/KT-14577) JS: do not report declaration clash when common redeclaration diagnostic applies
|
||||
- [`KT-15136`](https://youtrack.jetbrains.com/issue/KT-15136) JS: prohibit inheritance from kotlin Function{N} interfaces
|
||||
|
||||
#### Language features support
|
||||
- [`KT-12194`](https://youtrack.jetbrains.com/issue/KT-12194) Exhaustiveness check isn't generated for when expressions in JS at all
|
||||
- [`KT-15590`](https://youtrack.jetbrains.com/issue/KT-15590) Support increment on inlined properties
|
||||
|
||||
#### Native / external
|
||||
- [`KT-8081`](https://youtrack.jetbrains.com/issue/KT-8081) JS: native inherited class shouldn't require super or primary constructor call
|
||||
- [`KT-13892`](https://youtrack.jetbrains.com/issue/KT-13892) JS: restrictions for native (external) functions and properties
|
||||
- [`KT-15307`](https://youtrack.jetbrains.com/issue/KT-15307) JS: prohibit inline members inside external declarations
|
||||
- [`KT-15308`](https://youtrack.jetbrains.com/issue/KT-15308) JS: prohibit non-abstract members inside external interfaces except nullable properties (with accessors)
|
||||
|
||||
#### Exceptions / Errors
|
||||
- [`KT-7302`](https://youtrack.jetbrains.com/issue/KT-7302) KotlinJS - Trait with optional parameter causes compilation error
|
||||
- [`KT-15325`](https://youtrack.jetbrains.com/issue/KT-15325) JS: ReferenceError: $receiver is not defined
|
||||
- [`KT-15357`](https://youtrack.jetbrains.com/issue/KT-15357) JS: `when` expression in primary-from-secondary constructor call
|
||||
- [`KT-15435`](https://youtrack.jetbrains.com/issue/KT-15435) Call to 'synchronize' crashes JS backend
|
||||
- [`KT-15513`](https://youtrack.jetbrains.com/issue/KT-15513) JS: empty do..while loop crashes compiler
|
||||
|
||||
#### Various issues
|
||||
- [`KT-4160`](https://youtrack.jetbrains.com/issue/KT-4160) JS: compiler produces wrong code for escaped variable names with characters which Illegal in JS (e.g. spaces)
|
||||
- [`KT-7004`](https://youtrack.jetbrains.com/issue/KT-7004) JS: functions named `call` not inlined
|
||||
- [`KT-7588`](https://youtrack.jetbrains.com/issue/KT-7588) JS: operators are not inlined
|
||||
- [`KT-7733`](https://youtrack.jetbrains.com/issue/KT-7733) JS: Provide overflow behavior for integer arithmetic operations
|
||||
- [`KT-8413`](https://youtrack.jetbrains.com/issue/KT-8413) JS: generated wrong code for some float constants
|
||||
- [`KT-12598`](https://youtrack.jetbrains.com/issue/KT-12598) JS: comparisons for Enums always translates using strong operator
|
||||
- [`KT-13523`](https://youtrack.jetbrains.com/issue/KT-13523) Augmented assignment with array access in LHS is translated incorrectly
|
||||
- [`KT-13888`](https://youtrack.jetbrains.com/issue/KT-13888) JS: change how functions optional parameters get translated
|
||||
- [`KT-15260`](https://youtrack.jetbrains.com/issue/KT-15260) JS: don't import module more than once
|
||||
- [`KT-15475`](https://youtrack.jetbrains.com/issue/KT-15475) JS compiler deletes internal function name in js("") text block
|
||||
- [`KT-15506`](https://youtrack.jetbrains.com/issue/KT-15506) JS: invalid evaluation order when passing arguments to function by name
|
||||
- [`KT-15512`](https://youtrack.jetbrains.com/issue/KT-15512) JS: wrong result when use break/throw/return in || and && operators
|
||||
- [`KT-15569`](https://youtrack.jetbrains.com/issue/KT-15569) js: Wrong code generated when calling an overloaded operator function on an inherited property
|
||||
|
||||
### Standard Library
|
||||
- [`KEEP-23`](https://github.com/Kotlin/KEEP/blob/master/proposals/stdlib/group-and-fold.md) Operation to group by key and fold each group simultaneously
|
||||
- [`KT-15774`](https://youtrack.jetbrains.com/issue/KT-15774) `buildSequence` and `buildIterator` functions with `yield` and `yieldAll` based on coroutines
|
||||
- [`KT-6903`](https://youtrack.jetbrains.com/issue/KT-6903) Add `also` extension, which is like `apply`, but with `it` instead of `this` inside lambda.
|
||||
- [`KT-7858`](https://youtrack.jetbrains.com/issue/KT-7858) Add extension function `takeIf` to match a value against predicate and return null when it does not match
|
||||
- [`KT-11851`](https://youtrack.jetbrains.com/issue/KT-11851) Provide extension `Map.getValue(key: K): V` which throws or returns default when key is not found
|
||||
- [`KT-7417`](https://youtrack.jetbrains.com/issue/KT-7417) Add min, max on two numbers to standard library
|
||||
- [`KT-13898`](https://youtrack.jetbrains.com/issue/KT-13898) Allow to implement `toArray` in collections as protected and provide protected toArray in AbstractCollection.
|
||||
- [`KT-14935`](https://youtrack.jetbrains.com/issue/KT-14935) Array-like list instantiation functions: `List(count) { init }` and `MutableList(count) { init }`
|
||||
- [`KT-15630`](https://youtrack.jetbrains.com/issue/KT-15630) Overloads of mutableListOf, mutableSetOf, mutableMapOf without parameters
|
||||
- [`KT-15557`](https://youtrack.jetbrains.com/issue/KT-15557) Iterable<T>.joinTo loses information about each element by calling toString on them by default
|
||||
- [`KT-15477`](https://youtrack.jetbrains.com/issue/KT-15477) Introduce Throwable.addSuppressed extension
|
||||
- [`KT-15310`](https://youtrack.jetbrains.com/issue/KT-15310) Add dynamic.unsafeCast
|
||||
- [`KT-15436`](https://youtrack.jetbrains.com/issue/KT-15436) JS stdlib: org.w3c.fetch.RequestInit has 12 parameters, all required
|
||||
- [`KT-15458`](https://youtrack.jetbrains.com/issue/KT-15458) Add print and println to common stdlib
|
||||
|
||||
### IDE
|
||||
- Project View: Fix presentation of Kotlin files and their members when @JvmName having the same name as the file itself
|
||||
|
||||
#### no-arg / all-open
|
||||
- [`KT-15419`](https://youtrack.jetbrains.com/issue/KT-15419) IDE build doesn't pick settings of all-open plugin
|
||||
- [`KT-15686`](https://youtrack.jetbrains.com/issue/KT-15686) IDE build doesn't pick settings of no-arg plugin
|
||||
- [`KT-15735`](https://youtrack.jetbrains.com/issue/KT-15735) Facet loses compiler plugin settings on reopening project, when "Use project settings" = Yes
|
||||
|
||||
#### Formatter
|
||||
- [`KT-15542`](https://youtrack.jetbrains.com/issue/KT-15542) Formatter doesn't handle spaces around 'by' keyword
|
||||
- [`KT-15544`](https://youtrack.jetbrains.com/issue/KT-15544) Formatter doesn't remove spaces around function reference operator
|
||||
|
||||
#### Intention actions, inspections and quick-fixes
|
||||
|
||||
##### New features
|
||||
- Implement quickfix which enables/disables coroutine support in module or project
|
||||
- [`KT-5045`](https://youtrack.jetbrains.com/issue/KT-5045) Intention to convert between two comparisons and range check and vice versa
|
||||
- [`KT-5629`](https://youtrack.jetbrains.com/issue/KT-5629) Quick-fix to import extension method when arguments of non-extension method do not match
|
||||
- [`KT-6217`](https://youtrack.jetbrains.com/issue/KT-6217) Add warning for unused equals expression
|
||||
- [`KT-6824`](https://youtrack.jetbrains.com/issue/KT-6824) Quick-fix for applying spread operator where vararg is expected
|
||||
- [`KT-8855`](https://youtrack.jetbrains.com/issue/KT-8855) Implement "Create label" quick-fix
|
||||
- [`KT-15056`](https://youtrack.jetbrains.com/issue/KT-15056) Implement intention which converts object literal to class
|
||||
- [`KT-15068`](https://youtrack.jetbrains.com/issue/KT-15068) Implement intention which rename file according to the top-level class name
|
||||
- [`KT-15564`](https://youtrack.jetbrains.com/issue/KT-15564) Add quick-fix for changing primitive cast to primitive conversion method
|
||||
|
||||
##### Bug fixes
|
||||
- [`KT-14630`](https://youtrack.jetbrains.com/issue/KT-14630) Clearer diagnostic message for platform type inspection
|
||||
- [`KT-14745`](https://youtrack.jetbrains.com/issue/KT-14745) KNPE in convert primary constructor to secondary
|
||||
- [`KT-14889`](https://youtrack.jetbrains.com/issue/KT-14889) Replace 'if' with elvis operator produces red code if result is referenced in 'if'
|
||||
- [`KT-14907`](https://youtrack.jetbrains.com/issue/KT-14907) Quick-fix for missing operator adds infix modifier to created function
|
||||
- [`KT-15092`](https://youtrack.jetbrains.com/issue/KT-15092) Suppress inspection "use property access syntax" for some getters and fix completion for them
|
||||
- [`KT-15227`](https://youtrack.jetbrains.com/issue/KT-15227) "Replace if with elvis" silently changes semantics
|
||||
- [`KT-15412`](https://youtrack.jetbrains.com/issue/KT-15412) "Join declaration and assignment" can break code with smart casts
|
||||
- [`KT-15501`](https://youtrack.jetbrains.com/issue/KT-15501) Intention "Add names to call arguments" shouldn't appear when the only argument is a trailing lambda
|
||||
|
||||
#### Refactorings (Extract / Pull)
|
||||
- [`KT-15611`](https://youtrack.jetbrains.com/issue/KT-15611) Extract Interface/Superclass: Disable const-properties
|
||||
- Pull Up: Fix pull-up from object to superclass
|
||||
- [`KT-15602`](https://youtrack.jetbrains.com/issue/KT-15602) Extract Interface/Superclass: Disable "Make abstract" for inline/external/lateinit members
|
||||
- Extract Interface: Disable inline/external/lateinit members
|
||||
- [`KT-12704`](https://youtrack.jetbrains.com/issue/KT-12704), [`KT-15583`](https://youtrack.jetbrains.com/issue/KT-15583) Override/Implement Members: Support all nullability annotations respected by the Kotlin compiler
|
||||
- [`KT-15563`](https://youtrack.jetbrains.com/issue/KT-15563) Override Members: Allow overriding virtual synthetic members (e.g. equals(), hashCode(), toString(), etc.) in data classes
|
||||
- [`KT-15355`](https://youtrack.jetbrains.com/issue/KT-15355) Extract Interface: Disable "Make abstract" and assume it to be true for abstract members of an interface
|
||||
- [`KT-15353`](https://youtrack.jetbrains.com/issue/KT-15353) Extract Superclass/Interface: Allow extracting class with special name (and quotes)
|
||||
- [`KT-15643`](https://youtrack.jetbrains.com/issue/KT-15643) Extract Interface/Pull Up: Disable "Make abstract" and assume it to be true for primary constructor parameter when moving to an interface
|
||||
- [`KT-15607`](https://youtrack.jetbrains.com/issue/KT-15607) Extract Interface/Pull Up: Disable internal/protected members when moving to an interface
|
||||
- [`KT-15640`](https://youtrack.jetbrains.com/issue/KT-15640) Extract Interface/Pull Up: Drop 'final' modifier when moving to an interface
|
||||
- [`KT-15639`](https://youtrack.jetbrains.com/issue/KT-15639) Extract Superclass/Interface/Pull Up: Add spaces between 'abstract' modifier and annotations
|
||||
- [`KT-15606`](https://youtrack.jetbrains.com/issue/KT-15606) Extract Interface/Pull Up: Warn about private members with usages in the original class
|
||||
- [`KT-15635`](https://youtrack.jetbrains.com/issue/KT-15635) Extract Superclass/Interface: Fix bogus visibility warning inside a member when it's being moved as abstract
|
||||
- [`KT-15598`](https://youtrack.jetbrains.com/issue/KT-15598) Extract Interface: Red-highlight members inherited from a super-interface when that interface reference itself is not extracted
|
||||
- [`KT-15674`](https://youtrack.jetbrains.com/issue/KT-15674) Extract Superclass: Drop inapplicable modifiers when converting property-parameter to ordinary parameter
|
||||
|
||||
#### Multi-platform project support
|
||||
- [`KT-14908`](https://youtrack.jetbrains.com/issue/KT-14908) Actions (quick-fixes) to create implementations of header elements
|
||||
- [`KT-15305`](https://youtrack.jetbrains.com/issue/KT-15305) Do not report UNUSED for header declarations with implementations and vice versa
|
||||
- [`KT-15601`](https://youtrack.jetbrains.com/issue/KT-15601) Cannot suppress HEADER_WITHOUT_IMPLEMENTATION
|
||||
- [`KT-15641`](https://youtrack.jetbrains.com/issue/KT-15641) Quick-fix "Create header interface implementation" does nothing
|
||||
|
||||
#### Android support
|
||||
|
||||
- [`KT-12884`](https://youtrack.jetbrains.com/issue/KT-12884) Android Extensions: Refactor / Rename of activity name does not change import extension statement
|
||||
- [`KT-14308`](https://youtrack.jetbrains.com/issue/KT-14308) Android Studio randomly hangs due to Java static member import quick-fix lags
|
||||
- [`KT-14358`](https://youtrack.jetbrains.com/issue/KT-14358) Kotlin extensions: rename layout file: Throwable: "PSI and index do not match" through KotlinFullClassNameIndex.get()
|
||||
- [`KT-15483`](https://youtrack.jetbrains.com/issue/KT-15483) Kotlin lint throws unexpected exceptions in IDE
|
||||
|
||||
#### Various issues
|
||||
- [`KT-12872`](https://youtrack.jetbrains.com/issue/KT-12872) Don't show "defined in <very long qualifier here>" in quick doc for local variables
|
||||
- [`KT-13001`](https://youtrack.jetbrains.com/issue/KT-13001) "Go to Type Declaration" is broken for stdlib types
|
||||
- [`KT-13067`](https://youtrack.jetbrains.com/issue/KT-13067) Syntax colouring doesn't work for KDoc tags
|
||||
- [`KT-14815`](https://youtrack.jetbrains.com/issue/KT-14815) alt + enter -> "import" over a constructor reference is not working
|
||||
- [`KT-14819`](https://youtrack.jetbrains.com/issue/KT-14819) Quick documentation for special Enum functions doesn't work
|
||||
- [`KT-15141`](https://youtrack.jetbrains.com/issue/KT-15141) Bogus import popup for when function call cannot be resolved fully
|
||||
- [`KT-15154`](https://youtrack.jetbrains.com/issue/KT-15154) IllegalStateException on attempt to convert import statement to * if last added import is to typealias
|
||||
- [`KT-15329`](https://youtrack.jetbrains.com/issue/KT-15329) Regex not inspected properly for javaJavaIdentifierStart and javaJavaIdentifierPart
|
||||
- [`KT-15383`](https://youtrack.jetbrains.com/issue/KT-15383) Kotlin Scripts can only resolve stdlib functions/classes if they are in a source directory
|
||||
- [`KT-15440`](https://youtrack.jetbrains.com/issue/KT-15440) Improve extensions detection in IDEA
|
||||
- [`KT-15548`](https://youtrack.jetbrains.com/issue/KT-15548) Kotlin plugin: @Language injections specified in another module are ignored
|
||||
- Invoke `StorageComponentContainerContributor` extension for module dependencies container as well (needed for "sam-with-receiver" plugin to work with scripts)
|
||||
|
||||
### J2K
|
||||
- [`KT-6790`](https://youtrack.jetbrains.com/issue/KT-6790) J2K: Static import of Map.Entry is lost during conversion
|
||||
- [`KT-14736`](https://youtrack.jetbrains.com/issue/KT-14736) J2K: Incorrect conversion of back ticks in javadoc {@code} tag
|
||||
- [`KT-15027`](https://youtrack.jetbrains.com/issue/KT-15027) J2K: Annotations are set on functions, but not on property accessors
|
||||
|
||||
### Gradle support
|
||||
|
||||
- [`KT-15376`](https://youtrack.jetbrains.com/issue/KT-15376) Kotlin incremental=true: fixed compatibility with AS 2.3
|
||||
- [`KT-15433`](https://youtrack.jetbrains.com/issue/KT-15433) Kotlin daemon swallows exceptions: fixed stack trace reporting
|
||||
- [`KT-15682`](https://youtrack.jetbrains.com/issue/KT-15682) Uncheck "Use project settings" option on import Kotlin project from gradle
|
||||
|
||||
|
||||
## 1.1-M04 (EAP-4)
|
||||
|
||||
### Language related changes
|
||||
@@ -1062,23 +469,6 @@ These artifacts include extensions for the types available in the latter JDKs, s
|
||||
### IDE
|
||||
|
||||
- Project View: Fix presentation of Kotlin files and their members when @JvmName having the same name as the file itself
|
||||
- [`KT-15611`](https://youtrack.jetbrains.com/issue/KT-15611) Extract Interface/Superclass: Disable const-properties
|
||||
- Pull Up: Fix pull-up from object to superclass
|
||||
- [`KT-15602`](https://youtrack.jetbrains.com/issue/KT-15602) Extract Interface/Superclass: Disable "Make abstract" for inline/external/lateinit members
|
||||
- Extract Interface: Disable inline/external/lateinit members
|
||||
- [`KT-12704`](https://youtrack.jetbrains.com/issue/KT-12704), [`KT-15583`](https://youtrack.jetbrains.com/issue/KT-15583) Override/Implement Members: Support all nullability annotations respected by the Kotlin compiler
|
||||
- [`KT-15563`](https://youtrack.jetbrains.com/issue/KT-15563) Override Members: Allow overriding virtual synthetic members (e.g. equals(), hashCode(), toString(), etc.) in data classes
|
||||
- [`KT-15355`](https://youtrack.jetbrains.com/issue/KT-15355) Extract Interface: Disable "Make abstract" and assume it to be true for abstract members of an interface
|
||||
- [`KT-15353`](https://youtrack.jetbrains.com/issue/KT-15353) Extract Superclass/Interface: Allow extracting class with special name (and quotes)
|
||||
- [`KT-15643`](https://youtrack.jetbrains.com/issue/KT-15643) Extract Interface/Pull Up: Disable "Make abstract" and assume it to be true for primary constructor parameter when moving to an interface
|
||||
- [`KT-15607`](https://youtrack.jetbrains.com/issue/KT-15607) Extract Interface/Pull Up: Disable internal/protected members when moving to an interface
|
||||
- [`KT-15640`](https://youtrack.jetbrains.com/issue/KT-15640) Extract Interface/Pull Up: Drop 'final' modifier when moving to an interface
|
||||
- [`KT-15639`](https://youtrack.jetbrains.com/issue/KT-15639) Extract Superclass/Interface/Pull Up: Add spaces between 'abstract' modifier and annotations
|
||||
- [`KT-15606`](https://youtrack.jetbrains.com/issue/KT-15606) Extract Interface/Pull Up: Warn about private members with usages in the original class
|
||||
- [`KT-15635`](https://youtrack.jetbrains.com/issue/KT-15635) Extract Superclass/Interface: Fix bogus visibility warning inside a member when it's being moved as abstract
|
||||
- [`KT-15598`](https://youtrack.jetbrains.com/issue/KT-15598) Extract Interface: Red-highlight members inherited from a super-interface when that interface reference itself is not extracted
|
||||
- [`KT-15674`](https://youtrack.jetbrains.com/issue/KT-15674) Extract Superclass: Drop inapplicable modifiers when converting property-parameter to ordinary parameter
|
||||
- [`KT-15444`](https://youtrack.jetbrains.com/issue/KT-15444) Spring Support: Consider declaration open if it's supplemented with a preconfigured annotation in corresponding compiler plugin
|
||||
|
||||
#### Intention actions, inspections and quickfixes
|
||||
|
||||
@@ -1088,7 +478,6 @@ These artifacts include extensions for the types available in the latter JDKs, s
|
||||
- Implement quickfix which enables/disables coroutine support in module or project
|
||||
- [`KT-15056`](https://youtrack.jetbrains.com/issue/KT-15056) Implement intention which converts object literal to class
|
||||
- [`KT-8855`](https://youtrack.jetbrains.com/issue/KT-8855) Implement "Create label" quick fix
|
||||
- [`KT-15627`](https://youtrack.jetbrains.com/issue/KT-15627) Support "Change parameter type" for parameters with type-mismatched default value
|
||||
|
||||
## 1.0.6
|
||||
|
||||
|
||||
@@ -145,10 +145,10 @@
|
||||
</macrodef>
|
||||
|
||||
<target name="printStatistics">
|
||||
<print-file-size-statistic path="${kotlin-home}/lib" file-name="kotlin-stdlib.jar"/>
|
||||
<print-file-size-statistic path="${kotlin-home}/lib" file-name="kotlin-runtime.jar"/>
|
||||
<print-file-size-statistic path="${kotlin-home}/lib" file-name="kotlin-reflect.jar"/>
|
||||
|
||||
<print-file-size-statistic path="${kotlin-home}/lib" file-name="kotlin-stdlib-js.jar"/>
|
||||
<print-file-size-statistic path="${kotlin-home}/lib" file-name="kotlin-jslib.jar"/>
|
||||
<print-file-size-statistic path="${js.stdlib.output.dir}" file-name="kotlin.js"/>
|
||||
<print-file-size-statistic path="${js.stdlib.output.dir}" file-name="${compiled.stdlib.meta.js}"/>
|
||||
<print-file-size-statistic path="${js.stdlib.output.dir}" file-name="${compiled.stdlib.js}"/>
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.io.File
|
||||
class Kotlin2JsTask : KotlinCompilerBaseTask() {
|
||||
override val compilerFqName = "org.jetbrains.kotlin.cli.js.K2JSCompiler"
|
||||
|
||||
var libraries: Path? = null
|
||||
var library: Path? = null
|
||||
var outputPrefix: File? = null
|
||||
var outputPostfix: File? = null
|
||||
var sourceMap: Boolean = false
|
||||
@@ -35,9 +35,15 @@ class Kotlin2JsTask : KotlinCompilerBaseTask() {
|
||||
*/
|
||||
var main: String? = null
|
||||
|
||||
fun createLibraries(): Path {
|
||||
val libraryPaths = libraries ?: return Path(getProject()).also { libraries = it }
|
||||
return libraryPaths.createPath()
|
||||
fun createLibrary(): Path {
|
||||
val libraryPath = library
|
||||
if (libraryPath == null) {
|
||||
val t = Path(getProject())
|
||||
library = t
|
||||
return t
|
||||
}
|
||||
|
||||
return libraryPath.createPath()
|
||||
}
|
||||
|
||||
override fun fillSpecificArguments() {
|
||||
@@ -45,9 +51,9 @@ class Kotlin2JsTask : KotlinCompilerBaseTask() {
|
||||
args.add(output!!.canonicalPath)
|
||||
|
||||
// TODO: write test
|
||||
libraries?.let {
|
||||
args.add("-libraries")
|
||||
args.add(it.list().joinToString(File.pathSeparator) { File(it).canonicalPath })
|
||||
library?.let {
|
||||
args.add("-library-files")
|
||||
args.add(it.list().joinToString(separator = ",") { File(it).canonicalPath })
|
||||
}
|
||||
|
||||
outputPrefix?.let {
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.build
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.config.KotlinCompilerVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion
|
||||
|
||||
/**
|
||||
* If you want to add a new field, check its type is supported by [serializeToPlainText], [deserializeFromPlainText]
|
||||
*/
|
||||
data class JvmBuildMetaInfo(
|
||||
val isEAP: Boolean,
|
||||
val compilerBuildVersion: String,
|
||||
val languageVersionString: String,
|
||||
val apiVersionString: String,
|
||||
val coroutinesEnable: Boolean,
|
||||
val coroutinesWarn: Boolean,
|
||||
val coroutinesError: Boolean,
|
||||
val multiplatformEnable: Boolean,
|
||||
val metadataVersionMajor: Int,
|
||||
val metadataVersionMinor: Int,
|
||||
val metadataVersionPatch: Int,
|
||||
val bytecodeVersionMajor: Int,
|
||||
val bytecodeVersionMinor: Int,
|
||||
val bytecodeVersionPatch: Int,
|
||||
val ownVersion: Int = JvmBuildMetaInfo.OWN_VERSION,
|
||||
val coroutinesVersion: Int = JvmBuildMetaInfo.COROUTINES_VERSION,
|
||||
val multiplatformVersion: Int = JvmBuildMetaInfo.MULTIPLATFORM_VERSION
|
||||
) {
|
||||
companion object {
|
||||
const val OWN_VERSION: Int = 0
|
||||
const val COROUTINES_VERSION: Int = 0
|
||||
const val MULTIPLATFORM_VERSION: Int = 0
|
||||
|
||||
fun serializeToString(info: JvmBuildMetaInfo): String =
|
||||
serializeToPlainText(info)
|
||||
|
||||
fun deserializeFromString(str: String): JvmBuildMetaInfo? =
|
||||
deserializeFromPlainText(str)
|
||||
}
|
||||
}
|
||||
|
||||
fun JvmBuildMetaInfo(args: CommonCompilerArguments): JvmBuildMetaInfo =
|
||||
JvmBuildMetaInfo(isEAP = KotlinCompilerVersion.isPreRelease(),
|
||||
compilerBuildVersion = KotlinCompilerVersion.VERSION,
|
||||
languageVersionString = args.languageVersion ?: LanguageVersion.LATEST.versionString,
|
||||
apiVersionString = args.apiVersion ?: ApiVersion.LATEST.versionString,
|
||||
coroutinesEnable = args.coroutinesEnable,
|
||||
coroutinesWarn = args.coroutinesWarn,
|
||||
coroutinesError = args.coroutinesError,
|
||||
multiplatformEnable = args.multiPlatform,
|
||||
metadataVersionMajor = JvmMetadataVersion.INSTANCE.major,
|
||||
metadataVersionMinor = JvmMetadataVersion.INSTANCE.minor,
|
||||
metadataVersionPatch = JvmMetadataVersion.INSTANCE.patch,
|
||||
bytecodeVersionMajor = JvmBytecodeBinaryVersion.INSTANCE.major,
|
||||
bytecodeVersionMinor = JvmBytecodeBinaryVersion.INSTANCE.minor,
|
||||
bytecodeVersionPatch = JvmBytecodeBinaryVersion.INSTANCE.patch)
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.build
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.full.primaryConstructor
|
||||
|
||||
inline fun <reified T : Any> serializeToPlainText(instance: T): String = serializeToPlainText(instance, T::class)
|
||||
|
||||
fun <T : Any> serializeToPlainText(instance: T, klass: KClass<T>): String {
|
||||
val lines = ArrayList<String>()
|
||||
for (property in klass.memberProperties) {
|
||||
val value = property.get(instance)
|
||||
if (value != null) {
|
||||
lines.add("${property.name}=$value")
|
||||
}
|
||||
}
|
||||
return lines.joinToString("\n")
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> deserializeFromPlainText(str: String): T? = deserializeFromPlainText(str, T::class)
|
||||
|
||||
fun <T : Any> deserializeFromPlainText(str: String, klass: KClass<T>): T? {
|
||||
val args = ArrayList<Any?>()
|
||||
val properties = str
|
||||
.split("\n")
|
||||
.filter(String::isNotBlank)
|
||||
.associate { it.substringBefore("=") to it.substringAfter("=") }
|
||||
|
||||
val primaryConstructor = klass.primaryConstructor
|
||||
?: throw IllegalStateException("${klass.java} does not have primary constructor")
|
||||
for (param in primaryConstructor.parameters.sortedBy { it.index }) {
|
||||
val argumentString = properties[param.name]
|
||||
|
||||
if (argumentString == null) {
|
||||
if (param.type.isMarkedNullable) {
|
||||
args.add(null)
|
||||
continue
|
||||
}
|
||||
else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
val argument: Any? = when (param.type.classifier) {
|
||||
Int::class -> argumentString.toInt()
|
||||
Boolean::class -> argumentString.toBoolean()
|
||||
String::class -> argumentString
|
||||
else -> throw IllegalStateException("Unexpected property type: ${param.type}")
|
||||
}
|
||||
|
||||
args.add(argument)
|
||||
}
|
||||
|
||||
return primaryConstructor.call(*args.toTypedArray())
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import java.io.File
|
||||
|
||||
private val NORMAL_VERSION = 8
|
||||
private val EXPERIMENTAL_VERSION = 4
|
||||
private val DATA_CONTAINER_VERSION = 2
|
||||
private val DATA_CONTAINER_VERSION = 1
|
||||
|
||||
private val NORMAL_VERSION_FILE_NAME = "format-version.txt"
|
||||
private val EXPERIMENTAL_VERSION_FILE_NAME = "experimental-format-version.txt"
|
||||
|
||||
@@ -19,14 +19,14 @@ package org.jetbrains.kotlin.incremental
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||
import java.io.File
|
||||
|
||||
interface ICReporter {
|
||||
fun report(message: ()->String)
|
||||
abstract class ICReporter {
|
||||
abstract fun report(message: ()->String)
|
||||
|
||||
// used in Gradle plugin
|
||||
@Suppress("unused")
|
||||
fun reportCompileIteration(sourceFiles: Collection<File>, exitCode: ExitCode) {}
|
||||
open fun reportCompileIteration(sourceFiles: Iterable<File>, exitCode: ExitCode) {}
|
||||
|
||||
fun pathsAsString(files: Iterable<File>): String =
|
||||
open fun pathsAsString(files: Iterable<File>): String =
|
||||
files.map { it.canonicalPath }.joinToString()
|
||||
|
||||
fun pathsAsString(vararg files: File): String =
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.build
|
||||
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.config.KotlinCompilerVersion
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import org.junit.Test
|
||||
|
||||
class JvmBuildMetaInfoTest : TestCase() {
|
||||
@Test
|
||||
fun testSerialization() {
|
||||
val args = K2JVMCompilerArguments()
|
||||
val info = JvmBuildMetaInfo(args)
|
||||
val actual = JvmBuildMetaInfo.serializeToString(info)
|
||||
val expectedKeys = listOf(
|
||||
"apiVersionString",
|
||||
"bytecodeVersionMajor",
|
||||
"bytecodeVersionMinor",
|
||||
"bytecodeVersionPatch",
|
||||
"compilerBuildVersion",
|
||||
"coroutinesEnable",
|
||||
"coroutinesError",
|
||||
"coroutinesVersion",
|
||||
"coroutinesWarn",
|
||||
"isEAP",
|
||||
"languageVersionString",
|
||||
"metadataVersionMajor",
|
||||
"metadataVersionMinor",
|
||||
"metadataVersionPatch",
|
||||
"multiplatformEnable",
|
||||
"multiplatformVersion",
|
||||
"ownVersion"
|
||||
)
|
||||
assertEquals(expectedKeys, actual.split("\r\n", "\n").map { line -> line.split("=").first() })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSerializationDeserialization() {
|
||||
val args = K2JVMCompilerArguments()
|
||||
val info = JvmBuildMetaInfo(args)
|
||||
val serialized = JvmBuildMetaInfo.serializeToString(info)
|
||||
val deserialized = JvmBuildMetaInfo.deserializeFromString(serialized)
|
||||
assertEquals(info, deserialized)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEquals() {
|
||||
val args1 = K2JVMCompilerArguments()
|
||||
args1.coroutinesEnable = true
|
||||
val info1 = JvmBuildMetaInfo(args1)
|
||||
|
||||
val args2 = K2JVMCompilerArguments()
|
||||
args2.coroutinesEnable = false
|
||||
val info2 = JvmBuildMetaInfo(args2)
|
||||
|
||||
assertNotEquals(info1, info2)
|
||||
assertEquals(info1, info2.copy(coroutinesEnable = true))
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.build
|
||||
|
||||
import junit.framework.TestCase
|
||||
import org.junit.Test
|
||||
|
||||
class SerializationUtilsTest : TestCase() {
|
||||
data class TestPropertyTypes(
|
||||
val intNull: Int?,
|
||||
val int: Int,
|
||||
val stringNull: String?,
|
||||
val string: String,
|
||||
val boolNull: Boolean?,
|
||||
val bool: Boolean
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testPropertyTypes() {
|
||||
val instance1 = TestPropertyTypes(null, 1, null, "abc", null, false)
|
||||
val deserialized1 = deserializeFromPlainText<TestPropertyTypes>(serializeToPlainText(instance1))
|
||||
assertEquals(instance1, deserialized1)
|
||||
|
||||
val instance2 = TestPropertyTypes(1, 2, "abc", "xyz", true, false)
|
||||
val deserialized2 = deserializeFromPlainText<TestPropertyTypes>(serializeToPlainText(instance2))
|
||||
assertEquals(instance2, deserialized2)
|
||||
}
|
||||
|
||||
data class TestAddedField1(val x: Int)
|
||||
data class TestAddedField2(val x: Int, val y: Int?)
|
||||
|
||||
@Test
|
||||
fun testAddedField() {
|
||||
val testAddedField1 = TestAddedField1(1)
|
||||
val serialized = serializeToPlainText(testAddedField1)
|
||||
val deserialized = deserializeFromPlainText<TestAddedField2>(serialized)
|
||||
|
||||
assertEquals(TestAddedField2(1, null), deserialized)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20013,8 +20013,6 @@ public final class DebugProtoBuf {
|
||||
*isConst
|
||||
*lateinit
|
||||
*hasConstant
|
||||
*isExternal
|
||||
*isDelegated
|
||||
* </pre>
|
||||
*/
|
||||
boolean hasFlags();
|
||||
@@ -20032,8 +20030,6 @@ public final class DebugProtoBuf {
|
||||
*isConst
|
||||
*lateinit
|
||||
*hasConstant
|
||||
*isExternal
|
||||
*isDelegated
|
||||
* </pre>
|
||||
*/
|
||||
int getFlags();
|
||||
@@ -20389,8 +20385,6 @@ public final class DebugProtoBuf {
|
||||
*isConst
|
||||
*lateinit
|
||||
*hasConstant
|
||||
*isExternal
|
||||
*isDelegated
|
||||
* </pre>
|
||||
*/
|
||||
public boolean hasFlags() {
|
||||
@@ -20410,8 +20404,6 @@ public final class DebugProtoBuf {
|
||||
*isConst
|
||||
*lateinit
|
||||
*hasConstant
|
||||
*isExternal
|
||||
*isDelegated
|
||||
* </pre>
|
||||
*/
|
||||
public int getFlags() {
|
||||
@@ -21209,8 +21201,6 @@ public final class DebugProtoBuf {
|
||||
*isConst
|
||||
*lateinit
|
||||
*hasConstant
|
||||
*isExternal
|
||||
*isDelegated
|
||||
* </pre>
|
||||
*/
|
||||
public boolean hasFlags() {
|
||||
@@ -21230,8 +21220,6 @@ public final class DebugProtoBuf {
|
||||
*isConst
|
||||
*lateinit
|
||||
*hasConstant
|
||||
*isExternal
|
||||
*isDelegated
|
||||
* </pre>
|
||||
*/
|
||||
public int getFlags() {
|
||||
@@ -21251,8 +21239,6 @@ public final class DebugProtoBuf {
|
||||
*isConst
|
||||
*lateinit
|
||||
*hasConstant
|
||||
*isExternal
|
||||
*isDelegated
|
||||
* </pre>
|
||||
*/
|
||||
public Builder setFlags(int value) {
|
||||
@@ -21275,8 +21261,6 @@ public final class DebugProtoBuf {
|
||||
*isConst
|
||||
*lateinit
|
||||
*hasConstant
|
||||
*isExternal
|
||||
*isDelegated
|
||||
* </pre>
|
||||
*/
|
||||
public Builder clearFlags() {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
170
build.xml
170
build.xml
@@ -41,10 +41,9 @@
|
||||
|
||||
<include file="jslib_files.xml" />
|
||||
|
||||
<property name="compiled.builtins.js" value="builtins.js"/>
|
||||
<property name="compiled.stdlib.js" value="stdlib.js"/>
|
||||
<property name="compiled.stdlib.meta.js" value="kotlin.meta.js"/>
|
||||
<property name="stdlib.js.dir" value="${basedir}/js/js.libraries/src/js"/>
|
||||
<property name="stdlib.js.dir" value="${basedir}/js/js.translator/testData"/>
|
||||
|
||||
<!--
|
||||
The compiler produced on the first step of the build (Bootstrap No Tests) is only guaranteed to work against the OLD runtime
|
||||
@@ -314,7 +313,6 @@
|
||||
|
||||
<macrodef name="new-kotlin2js">
|
||||
<attribute name="output"/>
|
||||
<attribute name="additionalOptions" default=""/>
|
||||
<element name="src"/>
|
||||
|
||||
<sequential>
|
||||
@@ -342,10 +340,10 @@
|
||||
<arg value="@{output}"/>
|
||||
<arg value="-no-stdlib"/>
|
||||
<arg value="-version"/>
|
||||
<arg line="@{additionalOptions}"/>
|
||||
<arg value="-meta-info"/>
|
||||
<arg value="-kjsm"/>
|
||||
<arg line="-main noCall"/>
|
||||
<arg line="-module-kind commonjs"/>
|
||||
<arg value="-Xallow-kotlin-package"/>
|
||||
</java>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
@@ -368,16 +366,16 @@
|
||||
output="${js.stdlib.output.dir}/kotlin.js"
|
||||
outputWrapperFile="${stdlib.js.dir}/closure-wrapper.txt">
|
||||
|
||||
<path>
|
||||
<fileset dir="${stdlib.js.dir}">
|
||||
<include name="**/*.js"/>
|
||||
<exclude name="externs.js"/>
|
||||
</fileset>
|
||||
<fileset dir="${js.stdlib.output.dir}">
|
||||
<include name="${compiled.builtins.js}"/>
|
||||
<include name="${compiled.stdlib.js}"/>
|
||||
</fileset>
|
||||
</path>
|
||||
<sources dir="${stdlib.js.dir}">
|
||||
<file name="kotlin_lib_ecma5.js"/>
|
||||
<file name="kotlin_lib.js"/>
|
||||
<file name="long.js"/>
|
||||
</sources>
|
||||
|
||||
<sources dir="${js.stdlib.output.dir}">
|
||||
<file name="builtins.js"/>
|
||||
<file name="${compiled.stdlib.js}"/>
|
||||
</sources>
|
||||
|
||||
<externs dir="${stdlib.js.dir}">
|
||||
<file name="externs.js"/>
|
||||
@@ -409,7 +407,6 @@
|
||||
<target name="js-stdlib">
|
||||
<property environment="env"/>
|
||||
<kotlin-pp src="libraries/stdlib/src" output="${intermediate-sources}/stdlib/js" profile="JS" />
|
||||
<cleandir dir="${js.stdlib.output.dir}"/>
|
||||
|
||||
<!-- We don't want descriptors for built-ins to be serialized, so we compile these files separately. -->
|
||||
<new-kotlin2js output="${js.stdlib.output.dir}/tmp-builtins/kotlin.js">
|
||||
@@ -420,7 +417,7 @@
|
||||
</src>
|
||||
</new-kotlin2js>
|
||||
|
||||
<new-kotlin2js output="${js.stdlib.output.dir}/tmp/kotlin.js" additionalOptions="-meta-info">
|
||||
<new-kotlin2js output="${js.stdlib.output.dir}/tmp/kotlin.js">
|
||||
<src>
|
||||
<union>
|
||||
<fileset refid="kotlin.builtin.files"/>
|
||||
@@ -429,7 +426,7 @@
|
||||
</src>
|
||||
</new-kotlin2js>
|
||||
|
||||
<move file="${js.stdlib.output.dir}/tmp-builtins/kotlin.js" tofile="${js.stdlib.output.dir}/${compiled.builtins.js}" />
|
||||
<move file="${js.stdlib.output.dir}/tmp-builtins/kotlin.js" tofile="${js.stdlib.output.dir}/builtins.js" />
|
||||
<move file="${js.stdlib.output.dir}/tmp/kotlin.js" tofile="${js.stdlib.output.dir}/${compiled.stdlib.js}" />
|
||||
<move file="${js.stdlib.output.dir}/tmp/kotlin" todir="${js.stdlib.output.dir}" />
|
||||
<move file="${js.stdlib.output.dir}/tmp/${compiled.stdlib.meta.js}" tofile="${js.stdlib.output.dir}/${compiled.stdlib.meta.js}" />
|
||||
@@ -452,7 +449,7 @@
|
||||
<arg line="js-stdlib-merge" />
|
||||
</java>
|
||||
|
||||
<jar jarfile="${kotlin-home}/lib/kotlin-stdlib-js.jar" duplicate="fail">
|
||||
<jar jarfile="${kotlin-home}/lib/kotlin-jslib.jar" duplicate="fail">
|
||||
<zipfileset file="${kotlin-home}/build.txt" prefix="META-INF"/>
|
||||
<zipfileset dir="${js.stdlib.output.dir}" prefix="">
|
||||
<include name="kotlin.js"/>
|
||||
@@ -463,7 +460,7 @@
|
||||
<manifest>
|
||||
<attribute name="Built-By" value="${manifest.impl.vendor}"/>
|
||||
<attribute name="${manifest.impl.attribute.kotlin.version}" value="${manifest.impl.value.kotlin.version}"/>
|
||||
<attribute name="${manifest.impl.attribute.kotlin.runtime.component}" value="${manifest.impl.value.kotlin.runtime.component.main}"/>
|
||||
<attribute name="${manifest.impl.attribute.kotlin.runtime.component}" value="${manifest.impl.value.kotlin.runtime.component.core}"/>
|
||||
|
||||
<attribute name="Implementation-Vendor" value="${manifest.impl.vendor}"/>
|
||||
<attribute name="Implementation-Title" value="${manifest.impl.title.kotlin.javascript.stdlib}"/>
|
||||
@@ -471,28 +468,26 @@
|
||||
<attribute name="Specification-Title" value="${manifest.spec.title.kotlin.javascript.lib}"/>
|
||||
</manifest>
|
||||
</jar>
|
||||
<copy file="${kotlin-home}/lib/kotlin-stdlib-js.jar" tofile="${kotlin-home}/lib/kotlin-jslib.jar" />
|
||||
</target>
|
||||
|
||||
<target name="pack-js-stdlib-sources">
|
||||
<jar destfile="${kotlin-home}/lib/kotlin-stdlib-js-sources.jar" duplicate="fail">
|
||||
<jar destfile="${kotlin-home}/lib/kotlin-jslib-sources.jar" duplicate="fail">
|
||||
<resources refid="js.lib.files" />
|
||||
<fileset refid="kotlin.builtin.files" />
|
||||
|
||||
<manifest>
|
||||
<attribute name="Built-By" value="${manifest.impl.vendor}"/>
|
||||
<attribute name="${manifest.impl.attribute.kotlin.version}" value="${manifest.impl.value.kotlin.version}"/>
|
||||
<attribute name="${manifest.impl.attribute.kotlin.runtime.component}" value="${manifest.impl.value.kotlin.runtime.component.main}"/>
|
||||
<attribute name="${manifest.impl.attribute.kotlin.runtime.component}" value="${manifest.impl.value.kotlin.runtime.component.core}"/>
|
||||
|
||||
<attribute name="Implementation-Vendor" value="${manifest.impl.vendor}"/>
|
||||
<attribute name="Implementation-Title" value="${manifest.impl.title.kotlin.jvm.runtime.sources}"/>
|
||||
<attribute name="Implementation-Version" value="${build.number}"/>
|
||||
</manifest>
|
||||
</jar>
|
||||
<copy file="${kotlin-home}/lib/kotlin-stdlib-js-sources.jar" tofile="${kotlin-home}/lib/kotlin-jslib-sources.jar" />
|
||||
</target>
|
||||
|
||||
<target name="kotlin-js-stdlib" depends="js-stdlib,js-kotlin-test,pack-js-stdlib-sources"/>
|
||||
<target name="kotlin-js-stdlib" depends="js-stdlib,pack-js-stdlib-sources"/>
|
||||
|
||||
<target name="preloader">
|
||||
<cleandir dir="${output}/classes/preloader"/>
|
||||
@@ -617,6 +612,13 @@
|
||||
</target>
|
||||
|
||||
<target name="compiler">
|
||||
<taskdef resource="proguard/ant/task.properties">
|
||||
<classpath>
|
||||
<pathelement path="${dependencies}/proguard.jar"/>
|
||||
<pathelement path="${dependencies}/proguard-anttask.jar"/>
|
||||
</classpath>
|
||||
</taskdef>
|
||||
|
||||
<cleandir dir="${output}/classes/compiler"/>
|
||||
|
||||
<javac2 destdir="${output}/classes/compiler" debug="true" debuglevel="lines,vars,source" includeAntRuntime="false"
|
||||
@@ -638,32 +640,17 @@
|
||||
unless:true="${shrink}" />
|
||||
|
||||
<sequential if:true="${shrink}">
|
||||
<shrink configuration="${basedir}/compiler/compiler.pro"/>
|
||||
</sequential>
|
||||
|
||||
<pack-compiler-for-maven/>
|
||||
</target>
|
||||
|
||||
<macrodef name="shrink">
|
||||
<attribute name="configuration"/>
|
||||
|
||||
<sequential>
|
||||
<taskdef resource="proguard/ant/task.properties">
|
||||
<classpath>
|
||||
<pathelement path="${dependencies}/proguard.jar"/>
|
||||
<pathelement path="${dependencies}/proguard-anttask.jar"/>
|
||||
</classpath>
|
||||
</taskdef>
|
||||
|
||||
<available property="rtjar" value="${java.home}/lib/rt.jar" file="${java.home}/lib/rt.jar"/>
|
||||
<available property="rtjar" value="${java.home}/../Classes/classes.jar" file="${java.home}/../Classes/classes.jar"/>
|
||||
|
||||
<available property="jssejar" value="${java.home}/lib/jsse.jar" file="${java.home}/lib/jsse.jar"/>
|
||||
<available property="jssejar" value="${java.home}/../Classes/jsse.jar" file="${java.home}/../Classes/jsse.jar"/>
|
||||
|
||||
<proguard configuration="@{configuration}"/>
|
||||
<proguard configuration="${basedir}/compiler/compiler.pro"/>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
|
||||
<pack-compiler-for-maven/>
|
||||
</target>
|
||||
|
||||
<macrodef name="pack-compiler-for-maven">
|
||||
<sequential>
|
||||
@@ -1048,7 +1035,7 @@
|
||||
</macrodef>
|
||||
|
||||
<target name="builtins">
|
||||
<new-kotlinc output="${output}/classes/builtins" moduleName="kotlin-runtime">
|
||||
<new-kotlinc output="${output}/classes/builtins" moduleName="kotlin-builtins">
|
||||
<src>
|
||||
<include name="core/builtins/src"/>
|
||||
<include name="core/runtime.jvm/src"/>
|
||||
@@ -1073,37 +1060,18 @@
|
||||
</target>
|
||||
|
||||
<target name="kotlin-test">
|
||||
<path id="kotlin-test-compile-classpath">
|
||||
<pathelement location="${output}/builtins"/>
|
||||
<pathelement location="${output}/classes/builtins"/>
|
||||
<pathelement location="${output}/classes/stdlib"/>
|
||||
<pathelement location="libraries/lib/junit-4.11.jar"/>
|
||||
</path>
|
||||
|
||||
<java classname="org.jetbrains.kotlin.preloading.Preloader" failonerror="true" fork="true" maxmemory="${max.heap.size.for.forked.jvm}">
|
||||
<classpath>
|
||||
<pathelement location="${kotlin-home}/lib/kotlin-preloader.jar"/>
|
||||
</classpath>
|
||||
<assertions>
|
||||
<enable/>
|
||||
</assertions>
|
||||
<arg value="-cp"/>
|
||||
<arg value="${kotlin-home}/lib/kotlin-compiler.jar"/>
|
||||
<arg value="org.jetbrains.kotlin.cli.jvm.K2JVMCompiler"/>
|
||||
<arg value="-d"/>
|
||||
<arg value="${output}/classes/kotlin-test"/>
|
||||
<arg value="-version"/>
|
||||
<arg value="-no-stdlib"/>
|
||||
<arg value="-classpath"/>
|
||||
<arg value="${toString:kotlin-test-compile-classpath}"/>
|
||||
<arg value="-module-name"/>
|
||||
<arg value="kotlin-test"/>
|
||||
<arg value="-Xallow-kotlin-package"/>
|
||||
<arg value="-Xmulti-platform"/>
|
||||
<arg value="libraries/kotlin.test/common/src/main/kotlin"/>
|
||||
<arg value="libraries/kotlin.test/jvm/src/main/kotlin"/>
|
||||
<arg value="libraries/kotlin.test/junit/src/main/kotlin"/>
|
||||
</java>
|
||||
<new-kotlinc output="${output}/classes/kotlin-test" moduleName="kotlin-test">
|
||||
<src>
|
||||
<include name="libraries/kotlin.test/shared/src/main/kotlin" />
|
||||
<include name="libraries/kotlin.test/shared/src/main/kotlin.jvm" />
|
||||
<include name="libraries/kotlin.test/junit/src/main/kotlin" />
|
||||
</src>
|
||||
<class-path>
|
||||
<pathelement path="${output}/classes/builtins"/>
|
||||
<pathelement path="libraries/lib/junit-4.11.jar"/>
|
||||
<pathelement path="${output}/builtins"/>
|
||||
</class-path>
|
||||
</new-kotlinc>
|
||||
|
||||
<pack-runtime-jar jar-name="kotlin-test.jar" implementation-title="${manifest.impl.title.kotlin.test}" runtime-component="Test">
|
||||
<jar-content>
|
||||
@@ -1111,35 +1079,6 @@
|
||||
</jar-content>
|
||||
</pack-runtime-jar>
|
||||
</target>
|
||||
|
||||
<target name="js-kotlin-test">
|
||||
<java classname="org.jetbrains.kotlin.preloading.Preloader" failonerror="true" fork="true" maxmemory="${max.heap.size.for.forked.jvm}">
|
||||
<classpath>
|
||||
<pathelement location="${kotlin-home}/lib/kotlin-preloader.jar"/>
|
||||
</classpath>
|
||||
<assertions>
|
||||
<enable/>
|
||||
</assertions>
|
||||
<arg value="-cp"/>
|
||||
<arg value="${kotlin-home}/lib/kotlin-compiler.jar"/>
|
||||
<arg value="org.jetbrains.kotlin.cli.js.K2JSCompiler"/>
|
||||
<arg value="-output"/>
|
||||
<arg value="${output}/classes/kotlin-test-js/kotlin-test.js"/>
|
||||
<arg value="-version"/>
|
||||
<arg value="-meta-info"/>
|
||||
<arg line="-main noCall"/>
|
||||
<arg line="-module-kind umd"/>
|
||||
<arg value="-Xmulti-platform"/>
|
||||
<arg value="-Xallow-kotlin-package"/>
|
||||
<arg value="libraries/kotlin.test/common/src/main/kotlin"/>
|
||||
<arg value="libraries/kotlin.test/js/src/main/kotlin"/>
|
||||
</java>
|
||||
<pack-runtime-jar jar-name="kotlin-test-js.jar" implementation-title="${manifest.impl.title.kotlin.test}" runtime-component="TestJs">
|
||||
<jar-content>
|
||||
<fileset dir="${output}/classes/kotlin-test-js" includes="**/*" excludes="kotlin/internal/OnlyInputTypes*,kotlin/internal/InlineOnly*,kotlin/internal"/>
|
||||
</jar-content>
|
||||
</pack-runtime-jar>
|
||||
</target>
|
||||
|
||||
<target name="core">
|
||||
<new-kotlinc output="${output}/classes/core" moduleName="kotlin-core">
|
||||
@@ -1179,7 +1118,7 @@
|
||||
<attribute name="jar-dir" default="${kotlin-home}/lib"/>
|
||||
<attribute name="jar-name"/>
|
||||
<attribute name="implementation-title"/>
|
||||
<attribute name="runtime-component" default="${manifest.impl.value.kotlin.runtime.component.main}"/>
|
||||
<attribute name="runtime-component" default="${manifest.impl.value.kotlin.runtime.component.core}"/>
|
||||
<element name="jar-content"/>
|
||||
|
||||
<sequential>
|
||||
@@ -1203,7 +1142,7 @@
|
||||
</macrodef>
|
||||
|
||||
<target name="pack-runtime">
|
||||
<pack-runtime-jar jar-name="kotlin-stdlib.jar" implementation-title="${manifest.impl.title.kotlin.jvm.runtime}">
|
||||
<pack-runtime-jar jar-name="kotlin-runtime.jar" implementation-title="${manifest.impl.title.kotlin.jvm.runtime}">
|
||||
<jar-content>
|
||||
<fileset dir="${output}/classes/builtins"/>
|
||||
<fileset dir="${output}/classes/stdlib"/>
|
||||
@@ -1214,7 +1153,6 @@
|
||||
</zipfileset>
|
||||
</jar-content>
|
||||
</pack-runtime-jar>
|
||||
<copy file="${kotlin-home}/lib/kotlin-stdlib.jar" tofile="${kotlin-home}/lib/kotlin-runtime.jar"/>
|
||||
|
||||
<pack-runtime-jar jar-dir="${output}" jar-name="kotlin-reflect-before-jarjar.jar" implementation-title="${manifest.impl.title.kotlin.jvm.reflect}">
|
||||
<jar-content>
|
||||
@@ -1232,10 +1170,11 @@
|
||||
</manifest>
|
||||
</jar>
|
||||
|
||||
<delete file="${output}/kotlin-reflect-jarjar.jar" failonerror="false"/>
|
||||
|
||||
<sequential if:true="${obfuscate.reflect}">
|
||||
<taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask" classpath="dependencies/jarjar.jar"/>
|
||||
<delete file="${output}/kotlin-reflect-after-jarjar.jar" failonerror="false"/>
|
||||
<jarjar jarfile="${output}/kotlin-reflect-after-jarjar.jar" filesonly="true" filesetmanifest="merge">
|
||||
<jarjar jarfile="${output}/kotlin-reflect-jarjar.jar" filesonly="true" filesetmanifest="merge">
|
||||
<zipfileset src="${output}/kotlin-reflect-before-jarjar.jar"/>
|
||||
<rule pattern="org.jetbrains.kotlin.**" result="kotlin.reflect.jvm.internal.impl.@1"/>
|
||||
<rule pattern="javax.inject.**" result="kotlin.reflect.jvm.internal.impl.javax.inject.@1"/>
|
||||
@@ -1246,18 +1185,17 @@
|
||||
<compilerarg value="-script"/>
|
||||
<compilerarg value="kotlin/Metadata"/> <!-- Annotation to strip -->
|
||||
<compilerarg value="kotlin/reflect/jvm/internal/impl/.*"/> <!-- Classes to strip from -->
|
||||
<compilerarg value="${output}/kotlin-reflect-after-jarjar.jar"/>
|
||||
<compilerarg value="${output}/kotlin-reflect-before-proguard.jar"/>
|
||||
<compilerarg value="${output}/kotlin-reflect-jarjar.jar"/>
|
||||
<compilerarg value="${kotlin-home}/lib/kotlin-reflect.jar"/>
|
||||
<classpath>
|
||||
<pathelement location="${idea.sdk}/lib/asm-all.jar"/>
|
||||
</classpath>
|
||||
</kotlinc>
|
||||
|
||||
<shrink configuration="${basedir}/core/reflection.jvm/reflection.pro"/>
|
||||
</sequential>
|
||||
|
||||
<sequential unless:true="${obfuscate.reflect}">
|
||||
<echo message="Obfuscation of kotlin-reflect is disabled"/>
|
||||
<copy file="${output}/kotlin-reflect-before-jarjar.jar" tofile="${output}/kotlin-reflect-jarjar.jar" overwrite="true"/>
|
||||
<copy file="${output}/kotlin-reflect-before-jarjar.jar" tofile="${kotlin-home}/lib/kotlin-reflect.jar" overwrite="true"/>
|
||||
</sequential>
|
||||
</target>
|
||||
@@ -1290,7 +1228,7 @@
|
||||
</replaceregexp>
|
||||
</sequential>
|
||||
|
||||
<pack-runtime-jar jar-name="kotlin-stdlib-sources.jar" implementation-title="${manifest.impl.title.kotlin.jvm.runtime.sources}">
|
||||
<pack-runtime-jar jar-name="kotlin-runtime-sources.jar" implementation-title="${manifest.impl.title.kotlin.jvm.runtime.sources}">
|
||||
<jar-content>
|
||||
<fileset dir="${basedir}/core/builtins/native" includes="**/*"/>
|
||||
<fileset dir="${basedir}/core/builtins/src" includes="**/*"/>
|
||||
@@ -1300,8 +1238,6 @@
|
||||
<fileset dir="${output}/core.src" includes="**/*"/>
|
||||
</jar-content>
|
||||
</pack-runtime-jar>
|
||||
<copy file="${kotlin-home}/lib/kotlin-stdlib-sources.jar" tofile="${kotlin-home}/lib/kotlin-runtime-sources.jar"/>
|
||||
|
||||
|
||||
<pack-runtime-jar jar-dir="${output}" jar-name="kotlin-reflect-sources-for-maven.jar"
|
||||
implementation-title="${manifest.impl.title.kotlin.jvm.reflect.sources}">
|
||||
|
||||
@@ -5,7 +5,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.2.3'
|
||||
classpath 'com.android.tools.build:gradle:2.1.0'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
@@ -64,9 +64,7 @@ android {
|
||||
|
||||
dexOptions {
|
||||
dexInProcess false
|
||||
javaMaxHeapSize "700m"
|
||||
//default is 4 and Total Memory = maxProcessCount * javaMaxHeapSize
|
||||
maxProcessCount 2
|
||||
javaMaxHeapSize "600m"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.android.tests;
|
||||
|
||||
import org.jetbrains.kotlin.android.tests.download.SDKDownloader;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class PathManager {
|
||||
@@ -77,7 +75,7 @@ public class PathManager {
|
||||
}
|
||||
|
||||
public String getGradleBinFolder() {
|
||||
return getDependenciesRoot() + "/gradle-" + SDKDownloader.GRADLE_VERSION + "/bin";
|
||||
return getDependenciesRoot() + "/gradle-2.12/bin";
|
||||
}
|
||||
|
||||
public String getRootForDownload() {
|
||||
|
||||
@@ -43,7 +43,6 @@ public class SDKDownloader {
|
||||
private static final String SDK_TOOLS = "25.1.1";
|
||||
public static final String BUILD_TOOLS = "23.0.3";
|
||||
private static final int ANDROID_VERSION = 19;
|
||||
public static final String GRADLE_VERSION = "2.14.1";
|
||||
|
||||
|
||||
public SDKDownloader(PathManager pathManager) {
|
||||
@@ -79,7 +78,7 @@ public class SDKDownloader {
|
||||
}
|
||||
|
||||
public void downloadGradle() {
|
||||
download("https://services.gradle.org/distributions/gradle-" + GRADLE_VERSION + "-bin.zip", gradleZipPath);
|
||||
download("https://services.gradle.org/distributions/gradle-2.12-bin.zip", gradleZipPath);
|
||||
}
|
||||
|
||||
private static String getDownloadUrl(String prefix) {
|
||||
|
||||
@@ -32,8 +32,8 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys;
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration;
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys;
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.NameUtils;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
import org.jetbrains.kotlin.test.*;
|
||||
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase;
|
||||
@@ -244,11 +244,6 @@ public class CodegenTestsOnAndroidGenerator extends KtUsefulTestCase {
|
||||
continue;
|
||||
}
|
||||
|
||||
//TODO: support LANGUAGE_VERSION
|
||||
if (InTextDirectivesUtils.isDirectiveDefined(fullFileText, "LANGUAGE_VERSION:")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//TODO: support multifile facades
|
||||
//TODO: support multifile facades hierarchies
|
||||
if (hasBoxMethod(fullFileText)) {
|
||||
@@ -284,7 +279,7 @@ public class CodegenTestsOnAndroidGenerator extends KtUsefulTestCase {
|
||||
}
|
||||
|
||||
private String generateTestName(String fileName) {
|
||||
String result = NameUtils.sanitizeAsJavaIdentifier(FileUtil.getNameWithoutExtension(StringUtil.capitalize(fileName)));
|
||||
String result = JvmAbi.sanitizeAsJavaIdentifier(FileUtil.getNameWithoutExtension(StringUtil.capitalize(fileName)));
|
||||
|
||||
int i = 0;
|
||||
while (generatedTestNames.contains(result)) {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.backend.common.bridges.findInterfaceImplementation
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
@@ -155,12 +154,4 @@ object CodegenUtil {
|
||||
}
|
||||
return this[slice, whenExpression] == true
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun constructFakeFunctionCall(project: Project, referencedFunction: FunctionDescriptor): KtCallExpression {
|
||||
val fakeFunctionCall = StringBuilder("callableReferenceFakeCall(")
|
||||
fakeFunctionCall.append(referencedFunction.valueParameters.map { "p${it.index}" }.joinToString(", "))
|
||||
fakeFunctionCall.append(")")
|
||||
return KtPsiFactory(project).createExpression(fakeFunctionCall.toString()) as KtCallExpression
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,26 +19,12 @@ package org.jetbrains.kotlin.backend.common
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorEquivalenceForOverrides
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
|
||||
val SUSPEND_COROUTINE_OR_RETURN_NAME = Name.identifier("suspendCoroutineOrReturn")
|
||||
val COROUTINE_SUSPENDED_NAME = Name.identifier("COROUTINE_SUSPENDED")
|
||||
val SUSPEND_WITH_CURRENT_CONTINUATION_NAME = Name.identifier("suspendWithCurrentContinuation")
|
||||
val CONTINUATION_RESUME_METHOD_NAME = Name.identifier("resume")
|
||||
|
||||
val COROUTINES_INTRINSICS_PACKAGE_FQ_NAME = DescriptorUtils.COROUTINES_PACKAGE_FQ_NAME.child(Name.identifier("intrinsics"))
|
||||
|
||||
fun FunctionDescriptor.isBuiltInSuspendCoroutineOrReturn(): Boolean {
|
||||
if (name != SUSPEND_COROUTINE_OR_RETURN_NAME) return false
|
||||
|
||||
val originalDeclaration = getBuiltInSuspendCoroutineOrReturn() ?: return false
|
||||
|
||||
return DescriptorEquivalenceForOverrides.areEquivalent(
|
||||
originalDeclaration, this
|
||||
)
|
||||
}
|
||||
|
||||
fun FunctionDescriptor.getBuiltInSuspendCoroutineOrReturn() =
|
||||
module.getPackage(COROUTINES_INTRINSICS_PACKAGE_FQ_NAME).memberScope
|
||||
.getContributedFunctions(SUSPEND_COROUTINE_OR_RETURN_NAME, NoLookupLocation.FROM_BACKEND)
|
||||
fun FunctionDescriptor.getBuiltInSuspendWithCurrentContinuation() =
|
||||
builtIns.builtInsCoroutinePackageFragment.getMemberScope()
|
||||
.getContributedFunctions(SUSPEND_WITH_CURRENT_CONTINUATION_NAME, NoLookupLocation.FROM_BACKEND)
|
||||
.singleOrNull()
|
||||
|
||||
@@ -18,19 +18,13 @@ package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
public class AccessorForFunctionDescriptor extends AbstractAccessorForFunctionDescriptor implements AccessorForCallableDescriptor<FunctionDescriptor> {
|
||||
private final FunctionDescriptor calleeDescriptor;
|
||||
private final ClassDescriptor superCallTarget;
|
||||
private final String nameSuffix;
|
||||
|
||||
public AccessorForFunctionDescriptor(
|
||||
@NotNull FunctionDescriptor descriptor,
|
||||
@@ -42,7 +36,6 @@ public class AccessorForFunctionDescriptor extends AbstractAccessorForFunctionDe
|
||||
Name.identifier("access$" + nameSuffix));
|
||||
this.calleeDescriptor = descriptor;
|
||||
this.superCallTarget = superCallTarget;
|
||||
this.nameSuffix = nameSuffix;
|
||||
|
||||
initialize(DescriptorUtils.getReceiverParameterType(descriptor.getExtensionReceiverParameter()),
|
||||
descriptor instanceof ConstructorDescriptor || CodegenUtilKt.isJvmStaticInObjectOrClass(descriptor)
|
||||
@@ -53,28 +46,6 @@ public class AccessorForFunctionDescriptor extends AbstractAccessorForFunctionDe
|
||||
descriptor.getReturnType(),
|
||||
Modality.FINAL,
|
||||
Visibilities.LOCAL);
|
||||
|
||||
setSuspend(descriptor.isSuspend());
|
||||
if (descriptor.getUserData(CoroutineCodegenUtilKt.INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) != null) {
|
||||
userDataMap = new LinkedHashMap<UserDataKey<?>, Object>();
|
||||
userDataMap.put(
|
||||
CoroutineCodegenUtilKt.INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION,
|
||||
descriptor.getUserData(CoroutineCodegenUtilKt.INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected FunctionDescriptorImpl createSubstitutedCopy(
|
||||
@NotNull DeclarationDescriptor newOwner,
|
||||
@Nullable FunctionDescriptor original,
|
||||
@NotNull Kind kind,
|
||||
@Nullable Name newName,
|
||||
@NotNull Annotations annotations,
|
||||
@NotNull SourceElement source
|
||||
) {
|
||||
return new AccessorForFunctionDescriptor(calleeDescriptor, newOwner, superCallTarget, nameSuffix);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -76,8 +76,9 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implem
|
||||
boolean setterAccessorRequired
|
||||
) {
|
||||
super(containingDeclaration, null, Annotations.Companion.getEMPTY(), Modality.FINAL, Visibilities.LOCAL,
|
||||
original.isVar(), Name.identifier("access$" + nameSuffix), Kind.DECLARATION, SourceElement.NO_SOURCE,
|
||||
false, false, false, false, false, false);
|
||||
original.isVar(), Name.identifier("access$" + nameSuffix),
|
||||
Kind.DECLARATION, SourceElement.NO_SOURCE, /* lateInit = */ false, /* isConst = */ false,
|
||||
/* isHeader = */ false, /* isImpl = */ false, /* isExternal = */ false);
|
||||
|
||||
this.calleeDescriptor = original;
|
||||
this.superCallTarget = superCallTarget;
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
|
||||
@@ -32,12 +31,7 @@ abstract class ArgumentGenerator {
|
||||
*
|
||||
* @see kotlin.reflect.jvm.internal.KCallableImpl.callBy
|
||||
*/
|
||||
open fun generate(
|
||||
valueArgumentsByIndex: List<ResolvedValueArgument>,
|
||||
actualArgs: List<ResolvedValueArgument>,
|
||||
// may be null for a constructor of an object literal
|
||||
calleeDescriptor: CallableDescriptor?
|
||||
): DefaultCallArgs {
|
||||
open fun generate(valueArgumentsByIndex: List<ResolvedValueArgument>, actualArgs: List<ResolvedValueArgument>): DefaultCallArgs {
|
||||
assert(valueArgumentsByIndex.size == actualArgs.size) {
|
||||
"Value arguments collection should have same size, but ${valueArgumentsByIndex.size} != ${actualArgs.size}"
|
||||
}
|
||||
@@ -54,8 +48,7 @@ abstract class ArgumentGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
// Use unwrapped version, because additional synthetic parameters can't have default values
|
||||
val defaultArgs = DefaultCallArgs(calleeDescriptor?.unwrapFrontendVersion()?.valueParameters?.size ?: 0)
|
||||
val defaultArgs = DefaultCallArgs(valueArgumentsByIndex.size)
|
||||
|
||||
for (argumentWithDeclIndex in actualArgsWithDeclIndex) {
|
||||
val argument = argumentWithDeclIndex.arg
|
||||
|
||||
@@ -168,11 +168,6 @@ public class AsmUtil {
|
||||
return Type.getType(internalName.substring(1));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Type getArrayType(@NotNull Type componentType) {
|
||||
return Type.getType("[" + componentType.getDescriptor());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PrimitiveType asmPrimitiveTypeToLangPrimitiveType(Type type) {
|
||||
JvmPrimitiveType jvmPrimitiveType = primitiveTypeByAsmSort.get(type.getSort());
|
||||
@@ -186,7 +181,7 @@ public class AsmUtil {
|
||||
|
||||
public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind, GenerationState state) {
|
||||
return (functionDescriptor.getModality() == Modality.ABSTRACT ||
|
||||
(isJvmInterface(functionDescriptor.getContainingDeclaration()) && !state.isJvm8TargetWithDefaults()))
|
||||
(isJvmInterface(functionDescriptor.getContainingDeclaration()) && !state.isJvm8Target()))
|
||||
&& !isStaticMethod(kind, functionDescriptor);
|
||||
}
|
||||
|
||||
@@ -592,10 +587,6 @@ public class AsmUtil {
|
||||
v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "areEqual", "(Ljava/lang/Object;Ljava/lang/Object;)Z", false);
|
||||
}
|
||||
|
||||
public static void genIEEE754EqualForNullableTypesCall(InstructionAdapter v, Type left, Type right) {
|
||||
v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "areEqual", "(" + left.getDescriptor() + right.getDescriptor() + ")Z", false);
|
||||
}
|
||||
|
||||
public static void numConst(int value, Type type, InstructionAdapter v) {
|
||||
if (type == Type.FLOAT_TYPE) {
|
||||
v.fconst(value);
|
||||
@@ -770,7 +761,6 @@ public class AsmUtil {
|
||||
if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
|
||||
if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
|
||||
if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
|
||||
if (left == Type.CHAR_TYPE || right == Type.CHAR_TYPE) return Type.CHAR_TYPE;
|
||||
return Type.INT_TYPE;
|
||||
}
|
||||
|
||||
|
||||
@@ -210,12 +210,7 @@ class NumberCompare(
|
||||
) : BranchedValue(left, right, operandType, NumberCompare.getNumberCompareOpcode(opToken)) {
|
||||
|
||||
override fun patchOpcode(opcode: Int, v: InstructionAdapter): Int {
|
||||
// Opcode takes one int operand from the stack
|
||||
assert(opcode in IFEQ..IFLE) {
|
||||
"Opcode for comparing must be in range ${IFEQ..IFLE}, but $opcode was found"
|
||||
}
|
||||
|
||||
return when (operandType) {
|
||||
when (operandType) {
|
||||
Type.FLOAT_TYPE, Type.DOUBLE_TYPE -> {
|
||||
if (opToken == KtTokens.GT || opToken == KtTokens.GTEQ) {
|
||||
v.cmpl(operandType)
|
||||
@@ -223,19 +218,17 @@ class NumberCompare(
|
||||
else {
|
||||
v.cmpg(operandType)
|
||||
}
|
||||
|
||||
opcode
|
||||
}
|
||||
Type.LONG_TYPE -> {
|
||||
v.lcmp()
|
||||
|
||||
opcode
|
||||
}
|
||||
else -> {
|
||||
opcode + (IF_ICMPEQ - IFEQ)
|
||||
return opcode + (IF_ICMPEQ - IFEQ)
|
||||
}
|
||||
}
|
||||
return opcode
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getNumberCompareOpcode(opToken: IElementType): Int {
|
||||
return when (opToken) {
|
||||
@@ -269,4 +262,4 @@ class ObjectCompare(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,13 +17,10 @@
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
import org.jetbrains.kotlin.psi.ValueArgument;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*;
|
||||
import org.jetbrains.kotlin.types.FlexibleTypesKt;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
import java.util.List;
|
||||
@@ -56,12 +53,11 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator {
|
||||
@Override
|
||||
public DefaultCallArgs generate(
|
||||
@NotNull List<? extends ResolvedValueArgument> valueArgumentsByIndex,
|
||||
@NotNull List<? extends ResolvedValueArgument> valueArgs,
|
||||
@Nullable CallableDescriptor calleeDescriptor
|
||||
@NotNull List<? extends ResolvedValueArgument> valueArgs
|
||||
) {
|
||||
boolean shouldMarkLineNumbers = this.codegen.isShouldMarkLineNumbers();
|
||||
this.codegen.setShouldMarkLineNumbers(false);
|
||||
DefaultCallArgs defaultArgs = super.generate(valueArgumentsByIndex, valueArgs, calleeDescriptor);
|
||||
DefaultCallArgs defaultArgs = super.generate(valueArgumentsByIndex, valueArgs);
|
||||
this.codegen.setShouldMarkLineNumbers(shouldMarkLineNumbers);
|
||||
return defaultArgs;
|
||||
}
|
||||
@@ -88,9 +84,7 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator {
|
||||
protected void generateVararg(int i, @NotNull VarargValueArgument argument) {
|
||||
ValueParameterDescriptor parameter = valueParameters.get(i);
|
||||
Type type = valueParameterTypes.get(i);
|
||||
// Upper bound for type of vararg parameter should always have a form of 'Array<out T>',
|
||||
// while its lower bound may be Nothing-typed after approximation
|
||||
codegen.genVarargs(argument, FlexibleTypesKt.upperIfFlexible(parameter.getType()));
|
||||
codegen.genVarargs(argument, parameter.getType());
|
||||
callGenerator.afterParameterPut(type, null, i);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.INVOKESPECIAL
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.INVOKESTATIC
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
@@ -36,8 +35,7 @@ class CallableMethod(
|
||||
private val invokeOpcode: Int,
|
||||
override val dispatchReceiverType: Type?,
|
||||
override val extensionReceiverType: Type?,
|
||||
override val generateCalleeType: Type?,
|
||||
private val isInterfaceMethod: Boolean = Opcodes.INVOKEINTERFACE == invokeOpcode
|
||||
override val generateCalleeType: Type?
|
||||
) : Callable {
|
||||
fun getValueParameters(): List<JvmMethodParameterSignature> =
|
||||
signature.valueParameters
|
||||
@@ -53,13 +51,7 @@ class CallableMethod(
|
||||
|
||||
|
||||
override fun genInvokeInstruction(v: InstructionAdapter) {
|
||||
v.visitMethodInsn(
|
||||
invokeOpcode,
|
||||
owner.internalName,
|
||||
getAsmMethod().name,
|
||||
getAsmMethod().descriptor,
|
||||
isInterfaceMethod
|
||||
)
|
||||
v.visitMethodInsn(invokeOpcode, owner.internalName, getAsmMethod().name, getAsmMethod().descriptor)
|
||||
}
|
||||
|
||||
fun genInvokeDefaultInstruction(v: InstructionAdapter) {
|
||||
@@ -69,7 +61,7 @@ class CallableMethod(
|
||||
|
||||
val method = getAsmMethod()
|
||||
|
||||
if ("<init>" == method.name) {
|
||||
if ("<init>".equals(method.name)) {
|
||||
v.visitMethodInsn(INVOKESPECIAL, defaultImplOwner.internalName, "<init>", defaultMethodDesc, false)
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -26,8 +26,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
|
||||
import org.jetbrains.kotlin.codegen.context.ClosureContext;
|
||||
import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
|
||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension;
|
||||
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
|
||||
@@ -35,11 +33,13 @@ import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader;
|
||||
import org.jetbrains.kotlin.psi.KtElement;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
||||
@@ -62,6 +62,7 @@ import java.util.List;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConst;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLOSURE;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass;
|
||||
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.METHOD_FOR_FUNCTION;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
|
||||
@@ -197,7 +198,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
);
|
||||
}
|
||||
|
||||
protected void generateBridges() {
|
||||
private void generateBridges() {
|
||||
FunctionDescriptor erasedInterfaceFunction;
|
||||
if (samType == null) {
|
||||
erasedInterfaceFunction = getErasedInvokeFunction(funDescriptor);
|
||||
@@ -230,10 +231,9 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
|
||||
@Override
|
||||
protected void generateKotlinMetadataAnnotation() {
|
||||
FunctionDescriptor frontendFunDescriptor = CodegenUtilKt.unwrapFrontendVersion(funDescriptor);
|
||||
FunctionDescriptor freeLambdaDescriptor = createFreeLambdaDescriptor(frontendFunDescriptor);
|
||||
Method method = v.getSerializationBindings().get(METHOD_FOR_FUNCTION, frontendFunDescriptor);
|
||||
assert method != null : "No method for " + frontendFunDescriptor;
|
||||
FunctionDescriptor freeLambdaDescriptor = createFreeLambdaDescriptor(funDescriptor);
|
||||
Method method = v.getSerializationBindings().get(METHOD_FOR_FUNCTION, funDescriptor);
|
||||
assert method != null : "No method for " + funDescriptor;
|
||||
v.getSerializationBindings().put(METHOD_FOR_FUNCTION, freeLambdaDescriptor, method);
|
||||
|
||||
final DescriptorSerializer serializer =
|
||||
@@ -396,9 +396,6 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
}
|
||||
else if (container instanceof PackageFragmentDescriptor) {
|
||||
iv.aconst(state.getTypeMapper().mapOwner(descriptor));
|
||||
// Note that this name is not used in reflection. There should be the name of the referenced declaration's module instead,
|
||||
// but there's no nice API to obtain that name here yet
|
||||
// TODO: write the referenced declaration's module name and use it in reflection
|
||||
iv.aconst(state.getModuleName());
|
||||
iv.invokestatic(REFLECTION, "getOrCreateKotlinPackage",
|
||||
Type.getMethodDescriptor(K_DECLARATION_CONTAINER_TYPE, getType(Class.class), getType(String.class)), false);
|
||||
@@ -432,8 +429,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
iv.load(0, superClassAsmType);
|
||||
|
||||
String superClassConstructorDescriptor;
|
||||
if (superClassAsmType.equals(LAMBDA) || superClassAsmType.equals(FUNCTION_REFERENCE) ||
|
||||
superClassAsmType.equals(CoroutineCodegenUtilKt.COROUTINE_IMPL_ASM_TYPE)) {
|
||||
if (superClassAsmType.equals(LAMBDA) || superClassAsmType.equals(FUNCTION_REFERENCE) || superClassAsmType.equals(COROUTINE_IMPL)) {
|
||||
int arity = calculateArity();
|
||||
iv.iconst(arity);
|
||||
if (shouldHaveBoundReferenceReceiver) {
|
||||
@@ -470,6 +466,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
@NotNull CalculatedClosure closure,
|
||||
@NotNull Type ownerType
|
||||
) {
|
||||
BindingContext bindingContext = typeMapper.getBindingContext();
|
||||
List<FieldInfo> args = Lists.newArrayList();
|
||||
ClassDescriptor captureThis = closure.getCaptureThis();
|
||||
if (captureThis != null) {
|
||||
@@ -481,15 +478,23 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiverType), CAPTURED_RECEIVER_FIELD));
|
||||
}
|
||||
|
||||
for (EnclosedValueDescriptor enclosedValueDescriptor : closure.getCaptureVariables().values()) {
|
||||
DeclarationDescriptor descriptor = enclosedValueDescriptor.getDescriptor();
|
||||
if ((descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) ||
|
||||
ExpressionTypingUtils.isLocalFunction(descriptor)) {
|
||||
args.add(
|
||||
FieldInfo.createForHiddenField(
|
||||
ownerType, enclosedValueDescriptor.getType(), enclosedValueDescriptor.getFieldName()
|
||||
)
|
||||
);
|
||||
for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) {
|
||||
if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
|
||||
Type type = typeMapper.getSharedVarType(descriptor);
|
||||
if (type == null && descriptor instanceof LocalVariableDescriptor) {
|
||||
KotlinType delegateType = JvmCodegenUtil.getPropertyDelegateType((LocalVariableDescriptor) descriptor, bindingContext);
|
||||
if (delegateType != null) {
|
||||
type = typeMapper.mapType(delegateType);
|
||||
}
|
||||
}
|
||||
if (type == null) {
|
||||
type = typeMapper.mapType((VariableDescriptor) descriptor);
|
||||
}
|
||||
args.add(FieldInfo.createForHiddenField(ownerType, type, "$" + descriptor.getName().asString()));
|
||||
}
|
||||
else if (ExpressionTypingUtils.isLocalFunction(descriptor)) {
|
||||
Type classType = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor);
|
||||
args.add(FieldInfo.createForHiddenField(ownerType, classType, "$" + descriptor.getName().asString()));
|
||||
}
|
||||
else if (descriptor instanceof FunctionDescriptor) {
|
||||
assert captureReceiverType != null;
|
||||
|
||||
@@ -17,8 +17,12 @@
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
|
||||
|
||||
class ClosureGenerationStrategy(
|
||||
state: GenerationState,
|
||||
@@ -26,8 +30,35 @@ class ClosureGenerationStrategy(
|
||||
) : FunctionGenerationStrategy.FunctionDefault(state, declaration) {
|
||||
|
||||
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
|
||||
initializeVariablesForDestructuredLambdaParameters(codegen, codegen.context.functionDescriptor.valueParameters)
|
||||
processDestructuringInLambdaParameters(codegen)
|
||||
|
||||
super.doGenerateBody(codegen, signature)
|
||||
}
|
||||
|
||||
private fun processDestructuringInLambdaParameters(codegen: ExpressionCodegen) {
|
||||
val savedIsShouldMarkLineNumbers = codegen.isShouldMarkLineNumbers
|
||||
// Do not write line numbers until destructuring happens
|
||||
// (otherwise destructuring variables will be uninitialized in the beginning of lambda)
|
||||
codegen.isShouldMarkLineNumbers = false
|
||||
|
||||
for (parameterDescriptor in codegen.context.functionDescriptor.valueParameters) {
|
||||
if (parameterDescriptor !is ValueParameterDescriptorImpl.WithDestructuringDeclaration) continue
|
||||
|
||||
for (entry in parameterDescriptor.destructuringVariables.filterOutDescriptorsWithSpecialNames()) {
|
||||
codegen.myFrameMap.enter(entry, codegen.typeMapper.mapType(entry.type))
|
||||
}
|
||||
|
||||
val destructuringDeclaration =
|
||||
(DescriptorToSourceUtils.descriptorToDeclaration(parameterDescriptor) as? KtParameter)?.destructuringDeclaration
|
||||
?: error("Destructuring declaration for descriptor $parameterDescriptor not found")
|
||||
|
||||
codegen.initializeDestructuringDeclarationVariables(
|
||||
destructuringDeclaration,
|
||||
TransientReceiver(parameterDescriptor.type),
|
||||
codegen.findLocalOrCapturedValue(parameterDescriptor) ?: error("Local var not found for parameter $parameterDescriptor")
|
||||
)
|
||||
}
|
||||
|
||||
codegen.isShouldMarkLineNumbers = savedIsShouldMarkLineNumbers
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.FAKE_OVERRIDE
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.MutableClassDescriptor
|
||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.getSpecialSignatureInfo
|
||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.isBuiltinWithSpecialDescriptorInJvm
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
|
||||
|
||||
@@ -128,13 +128,11 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
|
||||
) {
|
||||
val typeMapper = state.typeMapper
|
||||
val isStatic = AsmUtil.isStaticMethod(contextKind, functionDescriptor)
|
||||
val baseMethodFlags = AsmUtil.getCommonCallableFlags(functionDescriptor) and Opcodes.ACC_VARARGS.inv()
|
||||
val remainingParameters = getRemainingParameters(functionDescriptor.original, substituteCount)
|
||||
val flags =
|
||||
baseMethodFlags or
|
||||
val flags = AsmUtil.getCommonCallableFlags(functionDescriptor) or
|
||||
(if (isStatic) Opcodes.ACC_STATIC else 0) or
|
||||
(if (functionDescriptor.modality == Modality.FINAL && functionDescriptor !is ConstructorDescriptor) Opcodes.ACC_FINAL else 0) or
|
||||
(if (remainingParameters.lastOrNull()?.varargElementType != null) Opcodes.ACC_VARARGS else 0)
|
||||
(if (functionDescriptor.modality == Modality.FINAL && functionDescriptor !is ConstructorDescriptor) Opcodes.ACC_FINAL else 0)
|
||||
|
||||
val remainingParameters = getRemainingParameters(functionDescriptor.original, substituteCount)
|
||||
val signature = typeMapper.mapSignature(functionDescriptor, contextKind, remainingParameters, false)
|
||||
val mv = classBuilder.newMethod(OtherOrigin(methodElement, functionDescriptor), flags,
|
||||
signature.asmMethod.name,
|
||||
@@ -148,7 +146,10 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
|
||||
mv.visitAnnotation(ANNOTATION_TYPE_DESCRIPTOR_FOR_JVMOVERLOADS_GENERATED_METHODS, /* visible = */ false)
|
||||
}
|
||||
|
||||
FunctionCodegen.generateParameterAnnotations(functionDescriptor, mv, signature, remainingParameters, memberCodegen, state)
|
||||
remainingParameters.withIndex().forEach {
|
||||
val annotationCodegen = AnnotationCodegen.forParameter(it.index, mv, memberCodegen, typeMapper)
|
||||
annotationCodegen.genAnnotations(it.value, signature.valueParameters[it.index].asmType)
|
||||
}
|
||||
|
||||
if (!state.classBuilderMode.generateBodies) {
|
||||
FunctionCodegen.generateLocalVariablesForParameters(mv, signature, null, Label(), Label(), remainingParameters, isStatic, typeMapper)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
* Copyright 2010-2016 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.
|
||||
@@ -50,8 +50,8 @@ import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.codegen.when.SwitchCodegen;
|
||||
import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil;
|
||||
import org.jetbrains.kotlin.config.ApiVersion;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
|
||||
@@ -61,7 +61,6 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
|
||||
import org.jetbrains.kotlin.load.kotlin.TypeSignatureMappingKt;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
|
||||
@@ -158,18 +157,43 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
this.v = new InstructionAdapter(mv);
|
||||
this.myFrameMap = frameMap;
|
||||
this.context = context;
|
||||
this.returnType = returnType;
|
||||
|
||||
FunctionDescriptor originalSuspendDescriptor = getOriginalSuspendDescriptor(context);
|
||||
if (originalSuspendDescriptor != null && originalSuspendDescriptor.getReturnType() != null) {
|
||||
this.returnType = getBoxedReturnTypeForSuspend(originalSuspendDescriptor);
|
||||
}
|
||||
else {
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
this.parentCodegen = parentCodegen;
|
||||
this.tailRecursionCodegen = new TailRecursionCodegen(context, this, this.v, state);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Type getBoxedReturnTypeForSuspend(FunctionDescriptor descriptorForSuspend) {
|
||||
assert descriptorForSuspend.getReturnType() != null : "Uninitialized suspend return type";
|
||||
return AsmUtil.boxType(typeMapper.mapType(descriptorForSuspend.getReturnType()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static FunctionDescriptor getOriginalSuspendLambdaDescriptorFromContext(MethodContext context) {
|
||||
private static FunctionDescriptor getOriginalSuspendDescriptor(MethodContext context) {
|
||||
FunctionDescriptor originalCoroutineDescriptor = getOriginalCoroutineDescriptor(context);
|
||||
if (originalCoroutineDescriptor != null) return originalCoroutineDescriptor;
|
||||
|
||||
if (context.getFunctionDescriptor().isSuspend()) {
|
||||
return (FunctionDescriptor) CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(context.getFunctionDescriptor());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static FunctionDescriptor getOriginalCoroutineDescriptor(MethodContext context) {
|
||||
if ((context.getParentContext() instanceof ClosureContext) &&
|
||||
(context.getParentContext().closure != null) &&
|
||||
context.getParentContext().closure.isSuspend()) {
|
||||
return ((ClosureContext) context.getParentContext()).getOriginalSuspendLambdaDescriptor();
|
||||
context.getParentContext().closure.isCoroutine()) {
|
||||
return ((ClosureContext) context.getParentContext()).getCoroutineDescriptor();
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -431,16 +455,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
return typeMapper.mapType(type);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Type expressionTypeForBranchingOperation(@Nullable KtExpression expression) {
|
||||
if (context.getFunctionDescriptor().isSuspend() &&
|
||||
!CoroutineCodegenUtilKt.isStateMachineNeeded(context.getFunctionDescriptor(), bindingContext) &&
|
||||
Boolean.TRUE.equals(bindingContext.get(IS_TAIL_EXPRESSION_IN_SUSPEND_FUNCTION, expression))) {
|
||||
return AsmTypes.OBJECT_TYPE;
|
||||
}
|
||||
return expressionType(expression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Type expressionType(@Nullable KtExpression expression) {
|
||||
return CodegenUtilKt.asmType(expression, typeMapper, bindingContext);
|
||||
@@ -481,7 +495,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
/* package */ StackValue generateIfExpression(@NotNull final KtIfExpression expression, final boolean isStatement) {
|
||||
final Type asmType = isStatement ? Type.VOID_TYPE : expressionTypeForBranchingOperation(expression);
|
||||
final Type asmType = isStatement ? Type.VOID_TYPE : expressionType(expression);
|
||||
final StackValue condition = gen(expression.getCondition());
|
||||
|
||||
final KtExpression thenExpression = expression.getThen();
|
||||
@@ -573,7 +587,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
blockStackElements.push(new LoopBlockStackElement(breakLabel, continueLabel, targetLabel(expression)));
|
||||
|
||||
PseudoInsnsKt.fakeAlwaysFalseIfeq(v, continueLabel);
|
||||
PseudoInsnsKt.fakeAlwaysFalseIfeq(v, breakLabel);
|
||||
|
||||
KtExpression body = expression.getBody();
|
||||
KtExpression condition = expression.getCondition();
|
||||
@@ -1518,10 +1531,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
KotlinType expectedType = bindingContext.getType(expression);
|
||||
if (expectedType == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return compileTimeValue.toConstantValue(expectedType);
|
||||
}
|
||||
|
||||
@@ -1640,7 +1649,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
declaration.getContainingFile()
|
||||
);
|
||||
|
||||
ClosureCodegen coroutineCodegen = CoroutineCodegen.createByLambda(this, descriptor, declaration, cv);
|
||||
ClosureCodegen coroutineCodegen = CoroutineCodegen.create(this, descriptor, declaration, cv);
|
||||
ClosureCodegen closureCodegen = coroutineCodegen != null ? coroutineCodegen : new ClosureCodegen(
|
||||
state, declaration, samType, context.intoClosure(descriptor, this, typeMapper),
|
||||
functionReferenceTarget, strategy, parentCodegen, cv
|
||||
@@ -1648,14 +1657,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
closureCodegen.generate();
|
||||
|
||||
return putClosureInstanceOnStack(closureCodegen, functionReferenceReceiver);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StackValue putClosureInstanceOnStack(
|
||||
@NotNull ClosureCodegen closureCodegen,
|
||||
@Nullable StackValue functionReferenceReceiver
|
||||
) {
|
||||
if (closureCodegen.getReifiedTypeParametersUsages().wereUsedReifiedParameters()) {
|
||||
ReifiedTypeInliner.putNeedClassReificationMarker(v);
|
||||
propagateChildReifiedTypeParametersUsages(closureCodegen.getReifiedTypeParametersUsages());
|
||||
@@ -1709,7 +1710,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
ArgumentGenerator argumentGenerator =
|
||||
new CallBasedArgumentGenerator(ExpressionCodegen.this, defaultCallGenerator, valueParameters, mappedTypes);
|
||||
|
||||
argumentGenerator.generate(valueArguments, valueArguments, null);
|
||||
argumentGenerator.generate(valueArguments, valueArguments);
|
||||
}
|
||||
|
||||
Collection<ClassConstructorDescriptor> constructors = classDescriptor.getConstructors();
|
||||
@@ -1747,7 +1748,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
if (captureReceiver != null) {
|
||||
StackValue capturedReceiver =
|
||||
functionReferenceReceiver != null ? functionReferenceReceiver :
|
||||
generateExtensionReceiver(unwrapOriginalReceiverOwnerForSuspendFunction(context));
|
||||
generateExtensionReceiver(unwrapOriginalLambdaDescriptorForCoroutine(context));
|
||||
callGenerator.putCapturedValueOnStack(capturedReceiver, capturedReceiver.type, paramIndex++);
|
||||
}
|
||||
|
||||
@@ -1768,36 +1769,16 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
);
|
||||
}
|
||||
|
||||
if (closure.isSuspend()) {
|
||||
if (closure.isCoroutine()) {
|
||||
// resultContinuation
|
||||
if (closure.isSuspendLambda()) {
|
||||
v.aconst(null);
|
||||
}
|
||||
else {
|
||||
assert context.getFunctionDescriptor().isSuspend() : "Coroutines closure must be created only inside suspend functions";
|
||||
ValueParameterDescriptor continuationParameter = CollectionsKt.last(context.getFunctionDescriptor().getValueParameters());
|
||||
StackValue continuationValue = findLocalOrCapturedValue(continuationParameter);
|
||||
|
||||
assert continuationValue != null : "Couldn't find a value for continuation parameter of " + context.getFunctionDescriptor();
|
||||
|
||||
callGenerator.putCapturedValueOnStack(continuationValue, continuationValue.type, paramIndex++);
|
||||
}
|
||||
v.aconst(null);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static CallableDescriptor unwrapOriginalReceiverOwnerForSuspendFunction(@NotNull MethodContext context) {
|
||||
FunctionDescriptor originalForDoResume =
|
||||
context.getFunctionDescriptor().getUserData(CoroutineCodegenUtilKt.INITIAL_SUSPEND_DESCRIPTOR_FOR_DO_RESUME);
|
||||
|
||||
if (originalForDoResume != null) {
|
||||
return originalForDoResume;
|
||||
}
|
||||
|
||||
if (context.getFunctionDescriptor().isSuspend()) {
|
||||
return CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(context.getFunctionDescriptor());
|
||||
}
|
||||
|
||||
private static CallableDescriptor unwrapOriginalLambdaDescriptorForCoroutine(@NotNull MethodContext context) {
|
||||
FunctionDescriptor coroutine = getOriginalSuspendDescriptor(context);
|
||||
if (coroutine != null) return coroutine;
|
||||
return context.getFunctionDescriptor();
|
||||
}
|
||||
|
||||
@@ -1888,17 +1869,17 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
@Nullable
|
||||
private StackValue getCoroutineInstanceValueForSuspensionPoint(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
FunctionDescriptor enclosingSuspendLambdaForSuspensionPoint =
|
||||
bindingContext.get(ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.getCall());
|
||||
CallableDescriptor enclosingSuspendLambdaForSuspensionPoint =
|
||||
bindingContext.get(ENCLOSING_SUSPEND_LAMBDA_FOR_SUSPENSION_POINT, resolvedCall.getCall());
|
||||
|
||||
if (enclosingSuspendLambdaForSuspensionPoint == null) return null;
|
||||
return genCoroutineInstanceBySuspendFunction(enclosingSuspendLambdaForSuspensionPoint);
|
||||
return genCoroutineInstanceByLambda(enclosingSuspendLambdaForSuspensionPoint);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private StackValue genCoroutineInstanceBySuspendFunction(@NotNull FunctionDescriptor suspendFunction) {
|
||||
if (!CoroutineCodegenUtilKt.isStateMachineNeeded(suspendFunction, bindingContext)) return null;
|
||||
ClassDescriptor suspendLambdaClassDescriptor = bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, suspendFunction);
|
||||
@NotNull
|
||||
private StackValue genCoroutineInstanceByLambda(@NotNull CallableDescriptor suspendLambda) {
|
||||
ClassDescriptor suspendLambdaClassDescriptor =
|
||||
bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, suspendLambda);
|
||||
assert suspendLambdaClassDescriptor != null : "Coroutine class descriptor should not be null";
|
||||
|
||||
return StackValue.thisOrOuter(this, suspendLambdaClassDescriptor, false, false);
|
||||
@@ -2227,7 +2208,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
FunctionDescriptor containingFunction =
|
||||
BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, true).getFirst();
|
||||
//FIRST_FUN_LABEL to prevent clashing with existing labels
|
||||
return new NonLocalReturnInfo(typeMapper.mapReturnType(containingFunction), InlineCodegenUtil.FIRST_FUN_LABEL);
|
||||
return new NonLocalReturnInfo(getReturnTypeForNonLocalReturn(containingFunction), InlineCodegenUtil.FIRST_FUN_LABEL);
|
||||
} else {
|
||||
//local
|
||||
return null;
|
||||
@@ -2239,18 +2220,27 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
DeclarationDescriptor elementDescriptor = typeMapper.getBindingContext().get(DECLARATION_TO_DESCRIPTOR, element);
|
||||
assert element != null : "Expression should be not null " + expression.getText();
|
||||
assert elementDescriptor != null : "Descriptor should be not null: " + element.getText();
|
||||
return new NonLocalReturnInfo(typeMapper.mapReturnType((CallableDescriptor) elementDescriptor), expression.getLabelName());
|
||||
return new NonLocalReturnInfo(getReturnTypeForNonLocalReturn(elementDescriptor), expression.getLabelName());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Type getReturnTypeForNonLocalReturn(DeclarationDescriptor elementDescriptor) {
|
||||
return (elementDescriptor instanceof AnonymousFunctionDescriptor
|
||||
&& ((AnonymousFunctionDescriptor) elementDescriptor).isCoroutine())
|
||||
|| (elementDescriptor instanceof FunctionDescriptor && ((FunctionDescriptor) elementDescriptor).isSuspend())
|
||||
? getBoxedReturnTypeForSuspend((FunctionDescriptor) elementDescriptor)
|
||||
: typeMapper.mapReturnType((CallableDescriptor) elementDescriptor);
|
||||
}
|
||||
|
||||
public void returnExpression(KtExpression expr) {
|
||||
boolean isBlockedNamedFunction = expr instanceof KtBlockExpression && expr.getParent() instanceof KtNamedFunction;
|
||||
|
||||
FunctionDescriptor originalSuspendLambdaDescriptor = getOriginalSuspendLambdaDescriptorFromContext(context);
|
||||
FunctionDescriptor originalCoroutineDescriptor = getOriginalCoroutineDescriptor(context);
|
||||
boolean isVoidCoroutineLambda =
|
||||
originalSuspendLambdaDescriptor != null && TypeSignatureMappingKt.hasVoidReturnType(originalSuspendLambdaDescriptor);
|
||||
originalCoroutineDescriptor != null && typeMapper.mapReturnType(originalCoroutineDescriptor).getSort() == Type.VOID;
|
||||
|
||||
// If generating body for named block-bodied function or Unit-typed coroutine lambda, generate it as sequence of statements
|
||||
Type typeForExpression =
|
||||
@@ -2502,14 +2492,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
public int lookupLocalIndex(DeclarationDescriptor descriptor) {
|
||||
int index = myFrameMap.getIndex(descriptor);
|
||||
if (index != -1) return index;
|
||||
return myFrameMap.getIndex(getParameterSynonymOrThis(descriptor));
|
||||
}
|
||||
|
||||
private DeclarationDescriptor getParameterSynonymOrThis(DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof ValueParameterDescriptor)) return descriptor;
|
||||
|
||||
if (!(descriptor instanceof ValueParameterDescriptor)) return -1;
|
||||
DeclarationDescriptor synonym = bindingContext.get(CodegenBinding.PARAMETER_SYNONYM, (ValueParameterDescriptor) descriptor);
|
||||
if (synonym == null) return -1;
|
||||
|
||||
return myFrameMap.getIndex(synonym);
|
||||
return synonym != null ? synonym : descriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -2600,7 +2590,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
if (!skipPropertyAccessors) {
|
||||
if (!couldUseDirectAccessToProperty(propertyDescriptor, true, isDelegatedProperty, context, state.getShouldInlineConstVals())) {
|
||||
propertyDescriptor = context.getAccessorForSuperCallIfNeeded(propertyDescriptor, superCallTarget, state);
|
||||
propertyDescriptor = context.getAccessorForSuperCallIfNeeded(propertyDescriptor, superCallTarget);
|
||||
|
||||
propertyDescriptor = context.accessibleDescriptor(propertyDescriptor, superCallTarget);
|
||||
|
||||
@@ -2737,9 +2727,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
if (originalIfSamAdapter != null) {
|
||||
descriptor = originalIfSamAdapter;
|
||||
}
|
||||
|
||||
descriptor = CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(descriptor);
|
||||
|
||||
// $default method is not private, so you need no accessor to call it
|
||||
return CallUtilKt.usesDefaultArguments(resolvedCall)
|
||||
? descriptor
|
||||
@@ -2770,7 +2757,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
FunctionDescriptor fd = accessibleFunctionDescriptor(resolvedCall);
|
||||
ClassDescriptor superCallTarget = getSuperCallTarget(call);
|
||||
|
||||
fd = context.getAccessorForSuperCallIfNeeded(fd, superCallTarget, state);
|
||||
fd = context.getAccessorForSuperCallIfNeeded(fd, superCallTarget);
|
||||
|
||||
Collection<ExpressionCodegenExtension> codegenExtensions = ExpressionCodegenExtension.Companion.getInstances(state.getProject());
|
||||
if (!codegenExtensions.isEmpty()) {
|
||||
@@ -2783,17 +2770,29 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
Callable callable = resolveToCallable(fd, superCallTarget != null, resolvedCall);
|
||||
|
||||
return callable.invokeMethodWithArguments(resolvedCall, receiver, this);
|
||||
|
||||
StackValue result = callable.invokeMethodWithArguments(resolvedCall, receiver, this);
|
||||
|
||||
if (bindingContext.get(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.getCall()) != null) {
|
||||
// Suspend function's calls inside another suspend function should behave like they leave values of correct type,
|
||||
// while real methods return java/lang/Object.
|
||||
// NB: They are always in return position at the moment.
|
||||
// If we didn't do this, StackValue.coerce would add proper CHECKCAST that would've failed in case of callee function
|
||||
// returning SUSPENDED marker, which is instance of java/lang/Object.
|
||||
return new OperationStackValue(returnType, ((OperationStackValue) result).getLambda());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private StackValue getContinuationParameterFromEnclosingSuspendFunction(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
FunctionDescriptor enclosingSuspendFunction =
|
||||
SimpleFunctionDescriptor enclosingSuspendFunction =
|
||||
bindingContext.get(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.getCall());
|
||||
|
||||
assert enclosingSuspendFunction != null
|
||||
: "Suspend functions may be called either as suspension points or from another suspend function";
|
||||
|
||||
FunctionDescriptor enclosingSuspendFunctionJvmView =
|
||||
SimpleFunctionDescriptor enclosingSuspendFunctionJvmView =
|
||||
bindingContext.get(CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, enclosingSuspendFunction);
|
||||
|
||||
assert enclosingSuspendFunctionJvmView != null : "No JVM view function found for " + enclosingSuspendFunction;
|
||||
@@ -2857,9 +2856,17 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
@NotNull CallGenerator callGenerator,
|
||||
@NotNull ArgumentGenerator argumentGenerator
|
||||
) {
|
||||
boolean isSuspensionPoint = CoroutineCodegenUtilKt.isSuspensionPointInStateMachine(resolvedCall, bindingContext);
|
||||
boolean isSuspensionPoint = CoroutineCodegenUtilKt.isSuspensionPoint(resolvedCall, bindingContext);
|
||||
if (isSuspensionPoint) {
|
||||
// Inline markers are used to spill the stack before coroutine suspension
|
||||
addInlineMarker(v, true);
|
||||
}
|
||||
boolean isConstructor = resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor;
|
||||
putReceiverAndInlineMarkerIfNeeded(callableMethod, resolvedCall, receiver, isSuspensionPoint, isConstructor);
|
||||
if (!isConstructor) { // otherwise already
|
||||
receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod);
|
||||
receiver.put(receiver.type, v);
|
||||
callableMethod.afterReceiverGeneration(v);
|
||||
}
|
||||
|
||||
callGenerator.processAndPutHiddenParameters(false);
|
||||
|
||||
@@ -2867,11 +2874,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
assert valueArguments != null : "Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor();
|
||||
|
||||
DefaultCallArgs defaultArgs =
|
||||
argumentGenerator.generate(
|
||||
valueArguments,
|
||||
new ArrayList<ResolvedValueArgument>(resolvedCall.getValueArguments().values()),
|
||||
resolvedCall.getResultingDescriptor()
|
||||
);
|
||||
argumentGenerator.generate(valueArguments, new ArrayList<ResolvedValueArgument>(resolvedCall.getValueArguments().values()));
|
||||
|
||||
if (tailRecursionCodegen.isTailRecursion(resolvedCall)) {
|
||||
tailRecursionCodegen.generateTailRecursion(resolvedCall);
|
||||
@@ -2914,78 +2917,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
}
|
||||
|
||||
private void putReceiverAndInlineMarkerIfNeeded(
|
||||
@NotNull Callable callableMethod,
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@NotNull StackValue receiver,
|
||||
boolean isSuspensionPoint,
|
||||
boolean isConstructor
|
||||
) {
|
||||
boolean isSafeCallOrOnStack = receiver instanceof StackValue.SafeCall || receiver instanceof StackValue.OnStack;
|
||||
|
||||
if (isSuspensionPoint && !isSafeCallOrOnStack) {
|
||||
// Inline markers are used to spill the stack before coroutine suspension
|
||||
addInlineMarker(v, true);
|
||||
}
|
||||
|
||||
if (!isConstructor) { // otherwise already
|
||||
receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod);
|
||||
receiver.put(receiver.type, v);
|
||||
|
||||
// In regular cases we add an inline marker just before receiver is loaded (to spill the stack before a suspension)
|
||||
// But in case of safe call things we get the following bytecode:
|
||||
|
||||
// ---- inlineMarkerBefore()
|
||||
// LOAD $receiver
|
||||
// IFNULL L1
|
||||
// ---- load the rest of the arguments
|
||||
// INVOKEVIRTUAL suspendCall()
|
||||
// ---- inlineMarkerBefore()
|
||||
// GOTO L2
|
||||
// L1
|
||||
// ACONST_NULL
|
||||
// L2
|
||||
// ...
|
||||
//
|
||||
// The problem is that the stack before the call is not restored in case of null receiver.
|
||||
// The solution is to spill stack just after receiver is loaded (after IFNULL) in case of safe call.
|
||||
// But the problem is that we should leave the receiver itself on the stack, so we store it in a temporary variable.
|
||||
if (isSuspensionPoint && isSafeCallOrOnStack) {
|
||||
boolean bothReceivers =
|
||||
receiver instanceof StackValue.CallReceiver
|
||||
&& ((StackValue.CallReceiver) receiver).getDispatchReceiver().type.getSort() != Type.VOID
|
||||
&& ((StackValue.CallReceiver) receiver).getExtensionReceiver().type.getSort() != Type.VOID;
|
||||
Type firstReceiverType =
|
||||
bothReceivers
|
||||
? ((StackValue.CallReceiver) receiver).getDispatchReceiver().type
|
||||
: receiver.type;
|
||||
|
||||
Type secondReceiverType = bothReceivers ? receiver.type : null;
|
||||
|
||||
int tmpVarForFirstReceiver = myFrameMap.enterTemp(firstReceiverType);
|
||||
int tmpVarForSecondReceiver = -1;
|
||||
|
||||
if (secondReceiverType != null) {
|
||||
tmpVarForSecondReceiver = myFrameMap.enterTemp(secondReceiverType);
|
||||
v.store(tmpVarForSecondReceiver, secondReceiverType);
|
||||
}
|
||||
v.store(tmpVarForFirstReceiver, firstReceiverType);
|
||||
|
||||
addInlineMarker(v, true);
|
||||
|
||||
v.load(tmpVarForFirstReceiver, firstReceiverType);
|
||||
if (secondReceiverType != null) {
|
||||
v.load(tmpVarForSecondReceiver, secondReceiverType);
|
||||
myFrameMap.leaveTemp(secondReceiverType);
|
||||
}
|
||||
|
||||
myFrameMap.leaveTemp(firstReceiverType);
|
||||
}
|
||||
|
||||
callableMethod.afterReceiverGeneration(v);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private CallGenerator getOrCreateCallGenerator(
|
||||
@NotNull CallableDescriptor descriptor,
|
||||
@@ -3029,8 +2960,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
@NotNull
|
||||
CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall<?> resolvedCall, @NotNull CallableDescriptor descriptor) {
|
||||
Map<TypeParameterDescriptor, KotlinType> typeArguments = getTypeArgumentsForResolvedCall(resolvedCall, descriptor);
|
||||
|
||||
Map<TypeParameterDescriptor, KotlinType> typeArguments = resolvedCall.getTypeArguments();
|
||||
TypeParameterMappings mappings = new TypeParameterMappings();
|
||||
for (Map.Entry<TypeParameterDescriptor, KotlinType> entry : typeArguments.entrySet()) {
|
||||
TypeParameterDescriptor key = entry.getKey();
|
||||
@@ -3055,38 +2985,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return getOrCreateCallGenerator(descriptor, resolvedCall.getCall().getCallElement(), mappings, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Map<TypeParameterDescriptor, KotlinType> getTypeArgumentsForResolvedCall(
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@NotNull CallableDescriptor descriptor
|
||||
) {
|
||||
if (!(descriptor instanceof TypeAliasConstructorDescriptor)) {
|
||||
return resolvedCall.getTypeArguments();
|
||||
}
|
||||
|
||||
TypeAliasConstructorDescriptor typeAliasConstructorDescriptor = (TypeAliasConstructorDescriptor) descriptor;
|
||||
ClassConstructorDescriptor underlyingConstructorDescriptor = typeAliasConstructorDescriptor.getUnderlyingConstructorDescriptor();
|
||||
KotlinType resultingType = typeAliasConstructorDescriptor.getReturnType();
|
||||
List<TypeProjection> typeArgumentsForReturnType = resultingType.getArguments();
|
||||
List<TypeParameterDescriptor> typeParameters = underlyingConstructorDescriptor.getTypeParameters();
|
||||
|
||||
assert typeParameters.size() == typeArgumentsForReturnType.size() :
|
||||
"Type parameters of the underlying constructor " + underlyingConstructorDescriptor +
|
||||
"should correspond to type arguments for the resulting type " + resultingType;
|
||||
|
||||
Map<TypeParameterDescriptor, KotlinType> typeArgumentsMap = Maps.newHashMapWithExpectedSize(typeParameters.size());
|
||||
for (TypeParameterDescriptor typeParameter: typeParameters) {
|
||||
KotlinType typeArgument = typeArgumentsForReturnType.get(typeParameter.getIndex()).getType();
|
||||
typeArgumentsMap.put(typeParameter, typeArgument);
|
||||
}
|
||||
|
||||
return typeArgumentsMap;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private static Pair<TypeParameterDescriptor, ReificationArgument> extractReificationArgument(@NotNull KotlinType type) {
|
||||
@@ -3196,7 +3097,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
boolean isSingleton = calleeContainingClass.getKind().isSingleton();
|
||||
if (isSingleton) {
|
||||
if (calleeContainingClass.equals(context.getThisDescriptor()) &&
|
||||
!CodegenUtilKt.isJvmStaticInObjectOrClass(context.getFunctionDescriptor())) {
|
||||
!CodegenUtilKt.isJvmStaticInObjectOrClass(context.getContextDescriptor())) {
|
||||
return StackValue.local(0, typeMapper.mapType(calleeContainingClass));
|
||||
}
|
||||
else if (isEnumEntry(calleeContainingClass)) {
|
||||
@@ -3423,7 +3324,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
@Override
|
||||
public Unit invoke(InstructionAdapter v) {
|
||||
KotlinType type = lhs.getType();
|
||||
if (lhs instanceof DoubleColonLHS.Expression && !((DoubleColonLHS.Expression) lhs).isObjectQualifier()) {
|
||||
if (lhs instanceof DoubleColonLHS.Expression && !((DoubleColonLHS.Expression) lhs).isObject()) {
|
||||
JavaClassProperty.INSTANCE.generateImpl(v, gen(receiverExpression));
|
||||
}
|
||||
else {
|
||||
@@ -3665,43 +3566,18 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
/*tries to use IEEE 754 arithmetic*/
|
||||
private StackValue genEqualsForExpressionsPreferIEEE754Arithmetic(
|
||||
@Nullable final KtExpression left,
|
||||
@Nullable final KtExpression right,
|
||||
@NotNull final IElementType opToken,
|
||||
@Nullable KtExpression left,
|
||||
@Nullable KtExpression right,
|
||||
@NotNull IElementType opToken,
|
||||
@NotNull Type leftType,
|
||||
@NotNull Type rightType,
|
||||
@Nullable final StackValue pregeneratedLeft
|
||||
@Nullable StackValue pregeneratedLeft
|
||||
) {
|
||||
assert (opToken == KtTokens.EQEQ || opToken == KtTokens.EXCLEQ) : "Optoken should be '==' or '!=', but: " + opToken;
|
||||
|
||||
final TypeAndNullability left754Type = calcTypeForIEEE754ArithmeticIfNeeded(left);
|
||||
final TypeAndNullability right754Type = calcTypeForIEEE754ArithmeticIfNeeded(right);
|
||||
if (left754Type != null && right754Type != null && left754Type.type.equals(right754Type.type)) {
|
||||
//check nullability cause there is some optimizations in codegen for non-nullable case
|
||||
if (left754Type.isNullable || right754Type.isNullable) {
|
||||
if (state.getLanguageVersionSettings().getApiVersion().compareTo(ApiVersion.KOTLIN_1_1) >= 0) {
|
||||
return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(InstructionAdapter v) {
|
||||
generate754EqualsForNullableTypesViaIntrinsic(v, opToken, pregeneratedLeft, left, left754Type, right, right754Type);
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(InstructionAdapter v) {
|
||||
generate754EqualsForNullableTypes(v, opToken, pregeneratedLeft, left, left754Type, right, right754Type);
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
leftType = left754Type.type;
|
||||
rightType = right754Type.type;
|
||||
}
|
||||
Type left754Type = calcTypeForIEEE754ArithmeticIfNeeded(left);
|
||||
Type right754Type = calcTypeForIEEE754ArithmeticIfNeeded(right);
|
||||
if (left754Type != null && right754Type != null && left754Type.equals(right754Type)) {
|
||||
leftType = left754Type;
|
||||
rightType = right754Type;
|
||||
}
|
||||
|
||||
return genEqualsForExpressionsOnStack(
|
||||
@@ -3711,126 +3587,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
);
|
||||
}
|
||||
|
||||
private void generate754EqualsForNullableTypesViaIntrinsic(
|
||||
@NotNull InstructionAdapter v,
|
||||
@NotNull IElementType opToken,
|
||||
@Nullable StackValue pregeneratedLeft,
|
||||
@Nullable KtExpression left,
|
||||
@NotNull TypeAndNullability left754Type,
|
||||
@Nullable KtExpression right,
|
||||
@NotNull TypeAndNullability right754Type
|
||||
) {
|
||||
Type leftType = left754Type.isNullable ? AsmUtil.boxType(left754Type.type) : left754Type.type;
|
||||
|
||||
if (pregeneratedLeft != null) {
|
||||
StackValue.coercion(pregeneratedLeft, leftType).put(leftType, v);
|
||||
}
|
||||
else {
|
||||
gen(left, leftType);
|
||||
}
|
||||
Type rightType = right754Type.isNullable ? AsmUtil.boxType(right754Type.type) : right754Type.type;
|
||||
gen(right, rightType);
|
||||
|
||||
AsmUtil.genIEEE754EqualForNullableTypesCall(v, leftType, rightType);
|
||||
|
||||
if (opToken == KtTokens.EXCLEQ) {
|
||||
genInvertBoolean(v);
|
||||
}
|
||||
}
|
||||
|
||||
private void generate754EqualsForNullableTypes(
|
||||
@NotNull InstructionAdapter v,
|
||||
@NotNull IElementType opToken,
|
||||
@Nullable StackValue pregeneratedLeft,
|
||||
@Nullable KtExpression left,
|
||||
@NotNull TypeAndNullability left754Type,
|
||||
@Nullable KtExpression right,
|
||||
@NotNull TypeAndNullability right754Type
|
||||
) {
|
||||
int equals = opToken == KtTokens.EQEQ ? 1 : 0;
|
||||
int notEquals = opToken != KtTokens.EQEQ ? 1 : 0;
|
||||
Label end = new Label();
|
||||
StackValue leftValue = pregeneratedLeft != null ? pregeneratedLeft : gen(left);
|
||||
leftValue.put(leftValue.type, v);
|
||||
leftValue = StackValue.onStack(leftValue.type);
|
||||
Type leftType = left754Type.type;
|
||||
Type rightType = right754Type.type;
|
||||
if (left754Type.isNullable) {
|
||||
leftValue.dup(v, false);
|
||||
Label leftIsNull = new Label();
|
||||
v.ifnull(leftIsNull);
|
||||
StackValue.coercion(leftValue, leftType).put(leftType, v);
|
||||
StackValue nonNullLeftValue = StackValue.onStack(leftType);
|
||||
|
||||
StackValue rightValue = gen(right);
|
||||
rightValue.put(rightValue.type, v);
|
||||
rightValue = StackValue.onStack(rightValue.type);
|
||||
if (right754Type.isNullable) {
|
||||
rightValue.dup(v, false);
|
||||
Label rightIsNotNull = new Label();
|
||||
v.ifnonnull(rightIsNotNull);
|
||||
AsmUtil.pop(v, rightValue.type);
|
||||
AsmUtil.pop(v, nonNullLeftValue.type);
|
||||
v.iconst(notEquals);
|
||||
v.goTo(end);
|
||||
v.mark(rightIsNotNull);
|
||||
}
|
||||
|
||||
StackValue.coercion(rightValue, rightType).put(rightType, v);
|
||||
StackValue nonNullRightValue = StackValue.onStack(rightType);
|
||||
StackValue.cmp(opToken, leftType, nonNullLeftValue, nonNullRightValue).put(Type.BOOLEAN_TYPE, v);
|
||||
v.goTo(end);
|
||||
|
||||
//left is null case
|
||||
v.mark(leftIsNull);
|
||||
AsmUtil.pop(v, leftValue.type);//pop null left
|
||||
rightValue = gen(right);
|
||||
rightValue.put(rightValue.type, v);
|
||||
rightValue = StackValue.onStack(rightValue.type);
|
||||
if (right754Type.isNullable) {
|
||||
Label rightIsNotNull = new Label();
|
||||
v.ifnonnull(rightIsNotNull);
|
||||
v.iconst(equals);
|
||||
v.goTo(end);
|
||||
v.mark(rightIsNotNull);
|
||||
v.iconst(notEquals);
|
||||
//v.goTo(end);
|
||||
}
|
||||
else {
|
||||
AsmUtil.pop(v, rightValue.type);
|
||||
v.iconst(notEquals);
|
||||
//v.goTo(end);
|
||||
}
|
||||
|
||||
v.mark(end);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
StackValue.coercion(leftValue, leftType).put(leftType, v);
|
||||
leftValue = StackValue.onStack(leftType);
|
||||
}
|
||||
|
||||
//right is nullable cause left is not
|
||||
StackValue rightValue = gen(right);
|
||||
rightValue.put(rightValue.type, v);
|
||||
rightValue = StackValue.onStack(rightValue.type);
|
||||
|
||||
rightValue.dup(v, false);
|
||||
Label rightIsNotNull = new Label();
|
||||
v.ifnonnull(rightIsNotNull);
|
||||
AsmUtil.pop(v, rightValue.type);
|
||||
AsmUtil.pop(v, leftValue.type);
|
||||
v.iconst(notEquals);
|
||||
v.goTo(end);
|
||||
|
||||
v.mark(rightIsNotNull);
|
||||
StackValue.coercion(rightValue, rightType).put(rightType, v);
|
||||
StackValue nonNullRightValue = StackValue.onStack(rightType);
|
||||
StackValue.cmp(opToken, leftType, leftValue, nonNullRightValue).put(Type.BOOLEAN_TYPE, v);
|
||||
|
||||
v.mark(end);
|
||||
}
|
||||
|
||||
private boolean isIntZero(KtExpression expr, Type exprType) {
|
||||
ConstantValue<?> exprValue = getPrimitiveOrStringCompileTimeConstant(expr, bindingContext, state.getShouldInlineConstVals());
|
||||
return isIntPrimitive(exprType) && exprValue != null && Integer.valueOf(0).equals(exprValue.getValue());
|
||||
@@ -3892,12 +3648,12 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
StackValue rightValue;
|
||||
Type leftType = expressionType(left);
|
||||
Type rightType = expressionType(right);
|
||||
TypeAndNullability left754Type = calcTypeForIEEE754ArithmeticIfNeeded(left);
|
||||
TypeAndNullability right754Type = calcTypeForIEEE754ArithmeticIfNeeded(right);
|
||||
Type left754Type = calcTypeForIEEE754ArithmeticIfNeeded(left);
|
||||
Type right754Type = calcTypeForIEEE754ArithmeticIfNeeded(right);
|
||||
Callable callable = resolveToCallable((FunctionDescriptor) resolvedCall.getResultingDescriptor(), false, resolvedCall);
|
||||
boolean is754Arithmetic = left754Type != null && right754Type != null && left754Type.type.equals(right754Type.type);
|
||||
boolean is754Arithmetic = left754Type != null && right754Type != null && left754Type.equals(right754Type);
|
||||
if (callable instanceof IntrinsicCallable && ((isPrimitive(leftType) && isPrimitive(rightType)) || is754Arithmetic)) {
|
||||
type = is754Arithmetic ? left754Type.type : comparisonOperandType(leftType, rightType);
|
||||
type = is754Arithmetic ? left754Type : comparisonOperandType(leftType, rightType);
|
||||
leftValue = gen(left);
|
||||
rightValue = gen(right);
|
||||
}
|
||||
@@ -3909,7 +3665,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
return StackValue.cmp(expression.getOperationToken(), type, leftValue, rightValue);
|
||||
}
|
||||
|
||||
private TypeAndNullability calcTypeForIEEE754ArithmeticIfNeeded(@Nullable KtExpression expression) {
|
||||
private Type calcTypeForIEEE754ArithmeticIfNeeded(@Nullable KtExpression expression) {
|
||||
return CodegenUtilKt.calcTypeForIEEE754ArithmeticIfNeeded(expression, bindingContext, context.getFunctionDescriptor());
|
||||
}
|
||||
|
||||
@@ -4509,7 +4265,9 @@ The "returned" value of try expression with no finally is either the last expres
|
||||
(or blocks).
|
||||
*/
|
||||
|
||||
final Type expectedAsmType = isStatement ? Type.VOID_TYPE : expressionTypeForBranchingOperation(expression);
|
||||
KotlinType jetType = bindingContext.getType(expression);
|
||||
assert jetType != null;
|
||||
final Type expectedAsmType = isStatement ? Type.VOID_TYPE : asmType(jetType);
|
||||
|
||||
return StackValue.operation(expectedAsmType, new Function1<InstructionAdapter, Unit>() {
|
||||
@Override
|
||||
@@ -4564,9 +4322,6 @@ The "returned" value of try expression with no finally is either the last expres
|
||||
int index = lookupLocalIndex(descriptor);
|
||||
v.store(index, descriptorType);
|
||||
|
||||
Label catchVariableStart = new Label();
|
||||
v.mark(catchVariableStart);
|
||||
|
||||
gen(catchBody, expectedAsmType);
|
||||
|
||||
if (!isStatement) {
|
||||
@@ -4578,8 +4333,8 @@ The "returned" value of try expression with no finally is either the last expres
|
||||
Label clauseEnd = new Label();
|
||||
v.mark(clauseEnd);
|
||||
|
||||
v.visitLocalVariable(descriptor.getName().asString(), descriptorType.getDescriptor(), null,
|
||||
catchVariableStart, clauseEnd, index);
|
||||
v.visitLocalVariable(descriptor.getName().asString(), descriptorType.getDescriptor(), null, clauseStart, clauseEnd,
|
||||
index);
|
||||
|
||||
genFinallyBlockOrGoto(finallyBlockStackElement, i != size - 1 || finallyBlock != null ? end : null, null);
|
||||
|
||||
@@ -4785,7 +4540,7 @@ The "returned" value of try expression with no finally is either the last expres
|
||||
final KtExpression expr = expression.getSubjectExpression();
|
||||
final Type subjectType = expressionType(expr);
|
||||
|
||||
final Type resultType = isStatement ? Type.VOID_TYPE : expressionTypeForBranchingOperation(expression);
|
||||
final Type resultType = isStatement ? Type.VOID_TYPE : expressionType(expression);
|
||||
|
||||
return StackValue.operation(resultType, new Function1<InstructionAdapter, Unit>() {
|
||||
@Override
|
||||
@@ -4911,8 +4666,7 @@ The "returned" value of try expression with no finally is either the last expres
|
||||
public NameGenerator getInlineNameGenerator() {
|
||||
NameGenerator nameGenerator = getParentCodegen().getInlineNameGenerator();
|
||||
Name name = context.getContextDescriptor().getName();
|
||||
String inlinedName = name.isSpecial() ? InlineCodegenUtil.SPECIAL_TRANSFORMATION_NAME : name.asString();
|
||||
return nameGenerator.subGenerator(inlinedName + InlineCodegenUtil.INLINE_CALL_TRANSFORMATION_SUFFIX);
|
||||
return nameGenerator.subGenerator((name.isSpecial() ? "$special" : name.asString()) + "$$inlined" );
|
||||
}
|
||||
|
||||
public Type getReturnType() {
|
||||
|
||||
@@ -31,8 +31,6 @@ import org.jetbrains.kotlin.backend.common.bridges.ImplKt;
|
||||
import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithOnlyTargetedAnnotations;
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.kotlin.codegen.context.*;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.SuspendFunctionGenerationStrategy;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
@@ -101,7 +99,7 @@ public class FunctionCodegen {
|
||||
private final Function1<DeclarationDescriptor, Boolean> IS_PURE_INTERFACE_CHECKER = new Function1<DeclarationDescriptor, Boolean>() {
|
||||
@Override
|
||||
public Boolean invoke(DeclarationDescriptor descriptor) {
|
||||
return JvmCodegenUtil.isAnnotationOrJvmInterfaceWithoutDefaults(descriptor, state);
|
||||
return JvmCodegenUtil.isAnnotationOrJvm6Interface(descriptor, state);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -121,29 +119,17 @@ public class FunctionCodegen {
|
||||
|
||||
public void gen(@NotNull KtNamedFunction function) {
|
||||
SimpleFunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, function);
|
||||
if (bindingContext.get(CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, functionDescriptor) != null) {
|
||||
functionDescriptor =
|
||||
(SimpleFunctionDescriptor) bindingContext.get(CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, functionDescriptor);
|
||||
}
|
||||
|
||||
if (functionDescriptor == null) {
|
||||
throw ExceptionLogger.logDescriptorNotFound("No descriptor for function " + function.getName(), function);
|
||||
}
|
||||
|
||||
if (owner.getContextKind() != OwnerKind.DEFAULT_IMPLS || function.hasBody()) {
|
||||
FunctionGenerationStrategy strategy;
|
||||
if (functionDescriptor.isSuspend()) {
|
||||
strategy = new SuspendFunctionGenerationStrategy(
|
||||
state,
|
||||
CoroutineCodegenUtilKt.<FunctionDescriptor>unwrapInitialDescriptorForSuspendFunction(functionDescriptor),
|
||||
function
|
||||
);
|
||||
}
|
||||
else {
|
||||
strategy = new FunctionGenerationStrategy.FunctionDefault(state, function);
|
||||
}
|
||||
if (bindingContext.get(CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, functionDescriptor) != null) {
|
||||
functionDescriptor = bindingContext.get(CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, functionDescriptor);
|
||||
}
|
||||
|
||||
generateMethod(JvmDeclarationOriginKt.OtherOrigin(function, functionDescriptor), functionDescriptor, strategy);
|
||||
if (owner.getContextKind() != OwnerKind.DEFAULT_IMPLS || function.hasBody()) {
|
||||
generateMethod(JvmDeclarationOriginKt.OtherOrigin(function, functionDescriptor), functionDescriptor,
|
||||
new FunctionGenerationStrategy.FunctionDefault(state, function));
|
||||
}
|
||||
|
||||
generateDefaultIfNeeded(owner.intoFunction(functionDescriptor, true), functionDescriptor, owner.getContextKind(),
|
||||
@@ -167,11 +153,6 @@ public class FunctionCodegen {
|
||||
@NotNull FunctionDescriptor descriptor,
|
||||
@NotNull FunctionGenerationStrategy strategy
|
||||
) {
|
||||
if (CoroutineCodegenUtilKt.isSuspendFunctionNotSuspensionView(descriptor)) {
|
||||
generateMethod(origin, CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(descriptor, bindingContext), strategy);
|
||||
return;
|
||||
}
|
||||
|
||||
generateMethod(origin, descriptor, owner.intoFunction(descriptor), strategy);
|
||||
}
|
||||
|
||||
@@ -209,11 +190,7 @@ public class FunctionCodegen {
|
||||
getThrownExceptions(functionDescriptor, typeMapper));
|
||||
|
||||
if (CodegenContextUtil.isImplClassOwner(owner)) {
|
||||
v.getSerializationBindings().put(
|
||||
METHOD_FOR_FUNCTION,
|
||||
CodegenUtilKt.<FunctionDescriptor>unwrapFrontendVersion(functionDescriptor),
|
||||
asmMethod
|
||||
);
|
||||
v.getSerializationBindings().put(METHOD_FOR_FUNCTION, functionDescriptor, asmMethod);
|
||||
}
|
||||
|
||||
generateMethodAnnotations(functionDescriptor, asmMethod, mv);
|
||||
@@ -224,14 +201,14 @@ public class FunctionCodegen {
|
||||
|
||||
generateBridges(functionDescriptor);
|
||||
|
||||
if (isJvm8InterfaceWithDefaultsMember(functionDescriptor, state) && contextKind != OwnerKind.DEFAULT_IMPLS && state.getGenerateDefaultImplsForJvm8()) {
|
||||
if (isJvm8InterfaceMember(functionDescriptor, state) && contextKind != OwnerKind.DEFAULT_IMPLS && state.getGenerateDefaultImplsForJvm8()) {
|
||||
generateDelegateForDefaultImpl(functionDescriptor, origin.getElement());
|
||||
}
|
||||
|
||||
boolean staticInCompanionObject = CodegenUtilKt.isJvmStaticInCompanionObject(functionDescriptor);
|
||||
if (staticInCompanionObject) {
|
||||
ImplementationBodyCodegen parentBodyCodegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
|
||||
parentBodyCodegen.addAdditionalTask(new JvmStaticInCompanionObjectGenerator(functionDescriptor, origin, state, parentBodyCodegen));
|
||||
parentBodyCodegen.addAdditionalTask(new JvmStaticGenerator(functionDescriptor, origin, state, parentBodyCodegen));
|
||||
}
|
||||
|
||||
if (!state.getClassBuilderMode().generateBodies || isAbstractMethod(functionDescriptor, contextKind, state)) {
|
||||
@@ -256,8 +233,7 @@ public class FunctionCodegen {
|
||||
else if (staticInCompanionObject) {
|
||||
// native @JvmStatic foo() in companion object should delegate to the static native function moved to the outer class
|
||||
mv.visitCode();
|
||||
FunctionDescriptor staticFunctionDescriptor = JvmStaticInCompanionObjectGenerator
|
||||
.createStaticFunctionDescriptor(functionDescriptor);
|
||||
FunctionDescriptor staticFunctionDescriptor = JvmStaticGenerator.createStaticFunctionDescriptor(functionDescriptor);
|
||||
Method accessorMethod =
|
||||
typeMapper.mapAsmMethod(memberCodegen.getContext().accessibleDescriptor(staticFunctionDescriptor, null));
|
||||
Type owningType = typeMapper.mapClass((ClassifierDescriptor) staticFunctionDescriptor.getContainingDeclaration());
|
||||
@@ -335,22 +311,9 @@ public class FunctionCodegen {
|
||||
@NotNull JvmMethodSignature jvmSignature,
|
||||
@NotNull InnerClassConsumer innerClassConsumer,
|
||||
@NotNull GenerationState state
|
||||
) {
|
||||
generateParameterAnnotations(
|
||||
functionDescriptor, mv, jvmSignature, functionDescriptor.getValueParameters(), innerClassConsumer, state
|
||||
);
|
||||
}
|
||||
|
||||
public static void generateParameterAnnotations(
|
||||
@NotNull FunctionDescriptor functionDescriptor,
|
||||
@NotNull MethodVisitor mv,
|
||||
@NotNull JvmMethodSignature jvmSignature,
|
||||
@NotNull List<ValueParameterDescriptor> valueParameters,
|
||||
@NotNull InnerClassConsumer innerClassConsumer,
|
||||
@NotNull GenerationState state
|
||||
) {
|
||||
KotlinTypeMapper typeMapper = state.getTypeMapper();
|
||||
Iterator<ValueParameterDescriptor> iterator = valueParameters.iterator();
|
||||
Iterator<ValueParameterDescriptor> iterator = functionDescriptor.getValueParameters().iterator();
|
||||
List<JvmMethodParameterSignature> kotlinParameterTypes = jvmSignature.getValueParameters();
|
||||
|
||||
for (int i = 0; i < kotlinParameterTypes.size(); i++) {
|
||||
@@ -456,7 +419,7 @@ public class FunctionCodegen {
|
||||
generateFacadeDelegateMethodBody(mv, signature.getAsmMethod(), (MultifileClassFacadeContext) context.getParentContext());
|
||||
methodEnd = new Label();
|
||||
}
|
||||
else if (OwnerKind.DEFAULT_IMPLS == context.getContextKind() && isJvm8InterfaceWithDefaultsMember(functionDescriptor, parentCodegen.state)) {
|
||||
else if (OwnerKind.DEFAULT_IMPLS == context.getContextKind() && isJvm8InterfaceMember(functionDescriptor, parentCodegen.state)) {
|
||||
int flags = AsmUtil.getMethodAsmFlags(functionDescriptor, OwnerKind.DEFAULT_IMPLS, context.getState());
|
||||
assert (flags & Opcodes.ACC_ABSTRACT) == 0 : "Interface method with body should be non-abstract" + functionDescriptor;
|
||||
Type type = typeMapper.mapOwner(functionDescriptor);
|
||||
@@ -761,7 +724,7 @@ public class FunctionCodegen {
|
||||
public void generateBridges(@NotNull FunctionDescriptor descriptor) {
|
||||
if (descriptor instanceof ConstructorDescriptor) return;
|
||||
if (owner.getContextKind() == OwnerKind.DEFAULT_IMPLS) return;
|
||||
if (isAnnotationOrJvmInterfaceWithoutDefaults(descriptor.getContainingDeclaration(), state)) return;
|
||||
if (isAnnotationOrJvm6Interface(descriptor.getContainingDeclaration(), state)) return;
|
||||
|
||||
// equals(Any?), hashCode(), toString() never need bridges
|
||||
if (isMethodOfAny(descriptor)) return;
|
||||
@@ -956,6 +919,8 @@ public class FunctionCodegen {
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
genDefaultSuperCallCheckIfNeeded(iv, functionDescriptor, defaultMethod);
|
||||
|
||||
loadExplicitArgumentsOnStack(OBJECT_TYPE, isStatic, signature, generator);
|
||||
|
||||
List<JvmMethodParameterSignature> mappedParameters = signature.getValueParameters();
|
||||
int capturedArgumentsCount = 0;
|
||||
while (capturedArgumentsCount < mappedParameters.size() &&
|
||||
@@ -984,15 +949,7 @@ public class FunctionCodegen {
|
||||
|
||||
iv.mark(loadArg);
|
||||
}
|
||||
}
|
||||
|
||||
// load arguments after defaults generation to avoid redundant stack normalization operations
|
||||
loadExplicitArgumentsOnStack(OBJECT_TYPE, isStatic, signature, generator);
|
||||
|
||||
for (int index = 0; index < valueParameters.size(); index++) {
|
||||
ValueParameterDescriptor parameterDescriptor = valueParameters.get(index);
|
||||
Type type = mappedParameters.get(capturedArgumentsCount + index).getAsmType();
|
||||
int parameterIndex = frameMap.getIndex(parameterDescriptor);
|
||||
generator.putValueIfNeeded(type, StackValue.local(parameterIndex, type));
|
||||
}
|
||||
|
||||
@@ -1129,14 +1086,14 @@ public class FunctionCodegen {
|
||||
ClassDescriptor parentClass = getSuperClassDescriptor((ClassDescriptor) descriptor.getContainingDeclaration());
|
||||
assert parentClass != null;
|
||||
String parentInternalName = typeMapper.mapClass(parentClass).getInternalName();
|
||||
iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor(), false);
|
||||
iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor());
|
||||
}
|
||||
else {
|
||||
if (isJvm8InterfaceWithDefaultsMember(descriptor, state)) {
|
||||
if (isJvm8InterfaceMember(descriptor, state)) {
|
||||
iv.invokeinterface(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor());
|
||||
}
|
||||
else {
|
||||
iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor(), false);
|
||||
iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1265,7 +1222,7 @@ public class FunctionCodegen {
|
||||
iv.invokeinterface(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor());
|
||||
}
|
||||
else {
|
||||
iv.invokevirtual(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor(), false);
|
||||
iv.invokevirtual(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor());
|
||||
}
|
||||
|
||||
StackValue stackValue = AsmUtil.genNotNullAssertions(
|
||||
@@ -1300,6 +1257,6 @@ public class FunctionCodegen {
|
||||
@NotNull GenerationState state
|
||||
) {
|
||||
assert isInterface(contextClass) : "'processInterface' method should be called only for interfaces, but: " + contextClass;
|
||||
return JvmCodegenUtil.isJvm8InterfaceWithDefaults(contextClass, state) ? kind != OwnerKind.DEFAULT_IMPLS : kind == OwnerKind.DEFAULT_IMPLS;
|
||||
return isJvm8Interface(contextClass, state) ? kind != OwnerKind.DEFAULT_IMPLS : kind == OwnerKind.DEFAULT_IMPLS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.codegen;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
@@ -37,8 +36,6 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isObject;
|
||||
|
||||
public class FunctionReferenceGenerationStrategy extends FunctionGenerationStrategy.CodegenBased {
|
||||
private final ResolvedCall<?> resolvedCall;
|
||||
private final FunctionDescriptor referencedFunction;
|
||||
@@ -77,7 +74,7 @@ public class FunctionReferenceGenerationStrategy extends FunctionGenerationStrat
|
||||
every argument boils down to calling LOAD with the corresponding index
|
||||
*/
|
||||
|
||||
KtCallExpression fakeExpression = CodegenUtil.constructFakeFunctionCall(state.getProject(), referencedFunction);
|
||||
KtCallExpression fakeExpression = constructFakeFunctionCall();
|
||||
final List<? extends ValueArgument> fakeArguments = fakeExpression.getValueArguments();
|
||||
|
||||
final ReceiverValue dispatchReceiver = computeAndSaveReceiver(signature, codegen, referencedFunction.getDispatchReceiverParameter());
|
||||
@@ -143,17 +140,25 @@ public class FunctionReferenceGenerationStrategy extends FunctionGenerationStrat
|
||||
v.areturn(returnType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private KtCallExpression constructFakeFunctionCall() {
|
||||
StringBuilder fakeFunctionCall = new StringBuilder("callableReferenceFakeCall(");
|
||||
for (Iterator<ValueParameterDescriptor> iterator = referencedFunction.getValueParameters().iterator(); iterator.hasNext(); ) {
|
||||
ValueParameterDescriptor descriptor = iterator.next();
|
||||
fakeFunctionCall.append("p").append(descriptor.getIndex());
|
||||
if (iterator.hasNext()) {
|
||||
fakeFunctionCall.append(", ");
|
||||
}
|
||||
}
|
||||
fakeFunctionCall.append(")");
|
||||
return (KtCallExpression) KtPsiFactoryKt.KtPsiFactory(state.getProject()).createExpression(fakeFunctionCall.toString());
|
||||
}
|
||||
|
||||
private void computeAndSaveArguments(@NotNull List<? extends ValueArgument> fakeArguments, @NotNull ExpressionCodegen codegen) {
|
||||
int receivers = (referencedFunction.getDispatchReceiverParameter() != null ? 1 : 0) +
|
||||
(referencedFunction.getExtensionReceiverParameter() != null ? 1 : 0) -
|
||||
(receiverType != null ? 1 : 0);
|
||||
|
||||
if (receivers < 0 && referencedFunction instanceof ConstructorDescriptor && isObject(referencedFunction.getContainingDeclaration().getContainingDeclaration())) {
|
||||
//reference to object nested class
|
||||
//TODO: seems problem should be fixed on frontend side (note that object instance are captured by generated class)
|
||||
receivers = 0;
|
||||
}
|
||||
|
||||
List<ValueParameterDescriptor> parameters = CollectionsKt.drop(functionDescriptor.getValueParameters(), receivers);
|
||||
for (int i = 0; i < parameters.size(); i++) {
|
||||
ValueParameterDescriptor parameter = parameters.get(i);
|
||||
|
||||
@@ -29,7 +29,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
||||
import org.jetbrains.kotlin.backend.common.DataClassMethodGenerator;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.kotlin.codegen.binding.MutableClosure;
|
||||
import org.jetbrains.kotlin.codegen.context.*;
|
||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
|
||||
@@ -234,7 +233,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
@Override
|
||||
protected void generateDefaultImplsIfNeeded() {
|
||||
if (isInterface(descriptor) && !isLocal && (!JvmCodegenUtil.isJvm8InterfaceWithDefaults(descriptor, state) || state.getGenerateDefaultImplsForJvm8())) {
|
||||
if (isInterface(descriptor) && !isLocal && (!isJvm8Interface(descriptor, state) || state.getGenerateDefaultImplsForJvm8())) {
|
||||
Type defaultImplsType = state.getTypeMapper().mapDefaultImpls(descriptor);
|
||||
ClassBuilder defaultImplsBuilder =
|
||||
state.getFactory().newVisitor(JvmDeclarationOriginKt.DefaultImpls(myClass.getPsiOrParent(), descriptor), defaultImplsType, myClass.getContainingKtFile());
|
||||
@@ -1294,14 +1293,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
|
||||
private void generateTraitMethods() {
|
||||
if (isAnnotationOrJvmInterfaceWithoutDefaults(descriptor, state)) return;
|
||||
if (isAnnotationOrJvm6Interface(descriptor, state)) return;
|
||||
|
||||
List<FunctionDescriptor> restrictedInheritance = new ArrayList<FunctionDescriptor>();
|
||||
for (Map.Entry<FunctionDescriptor, FunctionDescriptor> entry : CodegenUtil.getNonPrivateTraitMethods(descriptor).entrySet()) {
|
||||
FunctionDescriptor interfaceFun = entry.getKey();
|
||||
//skip java 8 default methods
|
||||
if (!CodegenUtilKt.isDefinitelyNotDefaultImplsMethod(interfaceFun) && !isJvm8InterfaceWithDefaultsMember(interfaceFun, state)) {
|
||||
if (state.isJvm8TargetWithDefaults() && !JvmCodegenUtil.isJvm8InterfaceWithDefaults(interfaceFun.getContainingDeclaration(), state)) {
|
||||
if (!CodegenUtilKt.isDefinitelyNotDefaultImplsMethod(interfaceFun) && !isJvm8InterfaceMember(interfaceFun, state)) {
|
||||
if (state.isJvm8Target() && !JvmCodegenUtil.isJvm8Interface(interfaceFun.getContainingDeclaration(), state)) {
|
||||
restrictedInheritance.add(interfaceFun);
|
||||
}
|
||||
else {
|
||||
@@ -1594,8 +1593,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
iv.iconst(ordinal);
|
||||
|
||||
List<KtSuperTypeListEntry> delegationSpecifiers = enumEntry.getSuperTypeListEntries();
|
||||
ResolvedCall<?> defaultArgumentsConstructorCall = CallUtilKt.getResolvedCall(enumEntry, bindingContext);
|
||||
boolean enumEntryHasSubclass = CodegenBinding.enumEntryNeedSubclass(bindingContext, classDescriptor);
|
||||
if (delegationSpecifiers.size() == 1 && !enumEntryNeedSubclass(bindingContext, enumEntry)) {
|
||||
ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(delegationSpecifiers.get(0), bindingContext);
|
||||
|
||||
@@ -1603,9 +1600,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
codegen.invokeMethodWithArguments(method, resolvedCall, StackValue.none());
|
||||
}
|
||||
else if (defaultArgumentsConstructorCall != null && !enumEntryHasSubclass) {
|
||||
codegen.invokeFunction(defaultArgumentsConstructorCall, StackValue.none()).put(Type.VOID_TYPE, iv);
|
||||
}
|
||||
else {
|
||||
iv.invokespecial(implClass.getInternalName(), "<init>", "(Ljava/lang/String;I)V", false);
|
||||
}
|
||||
|
||||
@@ -30,9 +30,10 @@ import org.jetbrains.kotlin.codegen.context.MethodContext;
|
||||
import org.jetbrains.kotlin.codegen.context.RootContext;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor;
|
||||
import org.jetbrains.kotlin.load.kotlin.*;
|
||||
import org.jetbrains.kotlin.psi.Call;
|
||||
@@ -63,11 +64,11 @@ public class JvmCodegenUtil {
|
||||
private JvmCodegenUtil() {
|
||||
}
|
||||
|
||||
public static boolean isAnnotationOrJvmInterfaceWithoutDefaults(@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state) {
|
||||
return isAnnotationOrJvmInterfaceWithoutDefaults(descriptor, state.isJvm8Target(), state.isJvm8TargetWithDefaults());
|
||||
public static boolean isAnnotationOrJvm6Interface(@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state) {
|
||||
return isAnnotationOrJvm6Interface(descriptor, state.isJvm8Target());
|
||||
}
|
||||
|
||||
private static boolean isAnnotationOrJvmInterfaceWithoutDefaults(@NotNull DeclarationDescriptor descriptor, boolean isJvm8Target, boolean isJvm8TargetWithDefaults) {
|
||||
public static boolean isAnnotationOrJvm6Interface(@NotNull DeclarationDescriptor descriptor, boolean isJvm8Target) {
|
||||
if (!isJvmInterface(descriptor)) {
|
||||
return false;
|
||||
}
|
||||
@@ -79,35 +80,23 @@ public class JvmCodegenUtil {
|
||||
KotlinJvmBinaryClass binaryClass = ((KotlinJvmBinarySourceElement) source).getBinaryClass();
|
||||
assert binaryClass instanceof FileBasedKotlinClass :
|
||||
"KotlinJvmBinaryClass should be subclass of FileBasedKotlinClass, but " + binaryClass;
|
||||
/*TODO need add some flags to compiled code*/
|
||||
return true || ((FileBasedKotlinClass) binaryClass).getClassVersion() == Opcodes.V1_6;
|
||||
return ((FileBasedKotlinClass) binaryClass).getClassVersion() == Opcodes.V1_6;
|
||||
}
|
||||
}
|
||||
return !isJvm8TargetWithDefaults;
|
||||
return !isJvm8Target;
|
||||
}
|
||||
|
||||
public static boolean isJvm8InterfaceWithDefaults(@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state) {
|
||||
return isJvm8InterfaceWithDefaults(descriptor, state.isJvm8Target(), state.isJvm8TargetWithDefaults());
|
||||
public static boolean isJvm8Interface(@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state) {
|
||||
return isJvm8Interface(descriptor, state.isJvm8Target());
|
||||
}
|
||||
|
||||
public static boolean isJvm8InterfaceWithDefaults(@NotNull DeclarationDescriptor descriptor, boolean isJvm8Target, boolean isJvm8TargetWithDefaults) {
|
||||
return DescriptorUtils.isInterface(descriptor) && !isAnnotationOrJvmInterfaceWithoutDefaults(descriptor, isJvm8Target, isJvm8TargetWithDefaults);
|
||||
public static boolean isJvm8Interface(@NotNull DeclarationDescriptor descriptor, boolean isJvm8Target) {
|
||||
return DescriptorUtils.isInterface(descriptor) && !isAnnotationOrJvm6Interface(descriptor, isJvm8Target);
|
||||
}
|
||||
|
||||
public static boolean isJvm8InterfaceWithDefaultsMember(@NotNull CallableMemberDescriptor descriptor, @NotNull GenerationState state) {
|
||||
public static boolean isJvm8InterfaceMember(@NotNull CallableMemberDescriptor descriptor, @NotNull GenerationState state) {
|
||||
DeclarationDescriptor declaration = descriptor.getContainingDeclaration();
|
||||
return isJvm8InterfaceWithDefaults(declaration, state);
|
||||
}
|
||||
|
||||
public static boolean isNonDefaultInterfaceMember(@NotNull CallableMemberDescriptor descriptor, @NotNull GenerationState state) {
|
||||
if (!isJvmInterface(descriptor.getContainingDeclaration())) {
|
||||
return false;
|
||||
}
|
||||
if (descriptor instanceof JavaCallableMemberDescriptor) {
|
||||
return descriptor.getModality() == Modality.ABSTRACT;
|
||||
}
|
||||
|
||||
return !isJvm8InterfaceWithDefaultsMember(descriptor, state);
|
||||
return isJvm8Interface(declaration, state);
|
||||
}
|
||||
|
||||
public static boolean isJvmInterface(DeclarationDescriptor descriptor) {
|
||||
@@ -126,7 +115,7 @@ public class JvmCodegenUtil {
|
||||
return closure.getCaptureThis() == null &&
|
||||
closure.getCaptureReceiverType() == null &&
|
||||
closure.getCaptureVariables().isEmpty() &&
|
||||
!closure.isSuspend();
|
||||
!closure.isCoroutine();
|
||||
}
|
||||
|
||||
private static boolean isCallInsideSameClassAsDeclared(@NotNull CallableMemberDescriptor descriptor, @NotNull CodegenContext context) {
|
||||
|
||||
@@ -17,24 +17,22 @@
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.builtins.createFunctionType
|
||||
import org.jetbrains.kotlin.codegen.coroutines.COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME
|
||||
import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
|
||||
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
||||
import org.jetbrains.kotlin.codegen.coroutines.createJvmSuspendFunctionView
|
||||
import org.jetbrains.kotlin.coroutines.isSuspendLambda
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.MutableClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
class JvmRuntimeTypes(module: ModuleDescriptor) {
|
||||
private val kotlinJvmInternalPackage = MutablePackageFragmentDescriptor(module, FqName("kotlin.jvm.internal"))
|
||||
private val kotlinCoroutinesJvmInternalPackage =
|
||||
MutablePackageFragmentDescriptor(module, COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME)
|
||||
|
||||
private fun klass(name: String) = lazy { createClass(kotlinJvmInternalPackage, name) }
|
||||
|
||||
@@ -42,7 +40,7 @@ class JvmRuntimeTypes(module: ModuleDescriptor) {
|
||||
private val functionReference: ClassDescriptor by klass("FunctionReference")
|
||||
private val localVariableReference: ClassDescriptor by klass("LocalVariableReference")
|
||||
private val mutableLocalVariableReference: ClassDescriptor by klass("MutableLocalVariableReference")
|
||||
private val coroutineImplClass by lazy { createClass(kotlinCoroutinesJvmInternalPackage, "CoroutineImpl") }
|
||||
private val coroutineImplClass by klass("CoroutineImpl")
|
||||
|
||||
private val propertyReferences: List<ClassDescriptor> by lazy {
|
||||
(0..2).map { i -> createClass(kotlinJvmInternalPackage, "PropertyReference$i") }
|
||||
@@ -52,6 +50,10 @@ class JvmRuntimeTypes(module: ModuleDescriptor) {
|
||||
(0..2).map { i -> createClass(kotlinJvmInternalPackage, "MutablePropertyReference$i") }
|
||||
}
|
||||
|
||||
private val suspendFunctions: List<ClassDescriptor> by lazy {
|
||||
(0..1).map { i -> createClass(kotlinJvmInternalPackage, "SuspendFunction$i", ClassKind.INTERFACE) }
|
||||
}
|
||||
|
||||
private fun createClass(
|
||||
packageFragment: PackageFragmentDescriptor,
|
||||
name: String,
|
||||
@@ -68,8 +70,8 @@ class JvmRuntimeTypes(module: ModuleDescriptor) {
|
||||
fun getSupertypesForClosure(descriptor: FunctionDescriptor): Collection<KotlinType> {
|
||||
|
||||
val actualFunctionDescriptor =
|
||||
if (descriptor.isSuspend)
|
||||
getOrCreateJvmSuspendFunctionView(descriptor)
|
||||
if (descriptor.isSuspendLambda)
|
||||
createJvmSuspendFunctionView(descriptor)
|
||||
else
|
||||
descriptor
|
||||
|
||||
@@ -82,13 +84,15 @@ class JvmRuntimeTypes(module: ModuleDescriptor) {
|
||||
actualFunctionDescriptor.returnType!!
|
||||
)
|
||||
|
||||
if (descriptor.isSuspend) {
|
||||
if (descriptor.isSuspendLambda) {
|
||||
return mutableListOf<KotlinType>().apply {
|
||||
add(coroutineImplClass.defaultType)
|
||||
add(functionType)
|
||||
|
||||
if (descriptor.isSuspendLambda) {
|
||||
add(functionType)
|
||||
}
|
||||
val parametersNumber =
|
||||
descriptor.valueParameters.size + (if (functionType.isExtensionFunctionType) 1 else 0)
|
||||
|
||||
addIfNotNull(suspendFunctions.getOrNull(parametersNumber)?.defaultType)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.Synthetic
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
|
||||
class JvmStaticInCompanionObjectGenerator(
|
||||
class JvmStaticGenerator(
|
||||
val descriptor: FunctionDescriptor,
|
||||
val declarationOrigin: JvmDeclarationOrigin,
|
||||
val state: GenerationState,
|
||||
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||
import org.jetbrains.kotlin.fileClasses.FileClasses;
|
||||
@@ -67,8 +66,7 @@ import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvm8InterfaceWithDefaultsMember;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isNonDefaultInterfaceMember;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvm8InterfaceMember;
|
||||
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
||||
@@ -238,20 +236,14 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
Annotations annotations = typeAliasDescriptor.getAnnotations();
|
||||
if (!isAnnotationsMethodOwner || annotations.getAllAnnotations().isEmpty()) return;
|
||||
|
||||
int flags = ACC_DEPRECATED | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC;
|
||||
String name = JvmAbi.getSyntheticMethodNameForAnnotatedTypeAlias(typeAliasDescriptor.getName());
|
||||
generateSyntheticAnnotationsMethod(typeAliasDescriptor, new Method(name, "()V"), annotations, null);
|
||||
}
|
||||
String desc = "()V";
|
||||
Method syntheticMethod = new Method(name, desc);
|
||||
|
||||
protected void generateSyntheticAnnotationsMethod(
|
||||
@NotNull MemberDescriptor descriptor,
|
||||
@NotNull Method syntheticMethod,
|
||||
@NotNull Annotations annotations,
|
||||
@Nullable AnnotationUseSiteTarget allowedTarget
|
||||
) {
|
||||
int flags = ACC_DEPRECATED | ACC_STATIC | ACC_SYNTHETIC | AsmUtil.getVisibilityAccessFlag(descriptor);
|
||||
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(descriptor), flags, syntheticMethod.getName(),
|
||||
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(typeAliasDescriptor), flags, syntheticMethod.getName(),
|
||||
syntheticMethod.getDescriptor(), null, null);
|
||||
AnnotationCodegen.forMethod(mv, this, typeMapper).genAnnotations(new AnnotatedSimple(annotations), Type.VOID_TYPE, allowedTarget);
|
||||
AnnotationCodegen.forMethod(mv, this, typeMapper).genAnnotations(new AnnotatedSimple(annotations), Type.VOID_TYPE, null);
|
||||
mv.visitCode();
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitEnd();
|
||||
@@ -385,7 +377,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
ClassDescriptor classDescriptor = ((ClassContext) outermost).getContextDescriptor();
|
||||
if (context instanceof MethodContext) {
|
||||
FunctionDescriptor functionDescriptor = ((MethodContext) context).getFunctionDescriptor();
|
||||
if (isInterface(functionDescriptor.getContainingDeclaration()) && !isJvm8InterfaceWithDefaultsMember(functionDescriptor, state)) {
|
||||
if (isInterface(functionDescriptor.getContainingDeclaration()) && !isJvm8InterfaceMember(functionDescriptor, state)) {
|
||||
return typeMapper.mapDefaultImpls(classDescriptor);
|
||||
}
|
||||
}
|
||||
@@ -499,11 +491,10 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
int indexOfDelegatedProperty = PropertyCodegen.indexOfDelegatedProperty(property);
|
||||
|
||||
StackValue delegateValue = PropertyCodegen.invokeDelegatedPropertyConventionMethodWithReceiver(
|
||||
codegen, typeMapper, provideDelegateResolvedCall, indexOfDelegatedProperty, 1,
|
||||
provideDelegateReceiver, propertyDescriptor
|
||||
);
|
||||
codegen, typeMapper, provideDelegateResolvedCall, indexOfDelegatedProperty, 1, provideDelegateReceiver);
|
||||
|
||||
propValue.store(delegateValue, codegen.v);
|
||||
|
||||
}
|
||||
|
||||
protected boolean shouldInitializeProperty(@NotNull KtProperty property) {
|
||||
@@ -591,7 +582,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
}
|
||||
if (delegatedProperties.isEmpty()) return;
|
||||
|
||||
v.newField(NO_ORIGIN, ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, JvmAbi.DELEGATED_PROPERTIES_ARRAY_NAME,
|
||||
v.newField(NO_ORIGIN, ACC_PRIVATE | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, JvmAbi.DELEGATED_PROPERTIES_ARRAY_NAME,
|
||||
"[" + K_PROPERTY_TYPE, null, null);
|
||||
|
||||
if (!state.getClassBuilderMode().generateBodies) return;
|
||||
@@ -780,7 +771,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
((AccessorForCallableDescriptor) accessorDescriptor).getSuperCallTarget() != null
|
||||
);
|
||||
|
||||
boolean hasDispatchReceiver = !isStaticDeclaration(functionDescriptor) && !isNonDefaultInterfaceMember(functionDescriptor, state);
|
||||
boolean hasDispatchReceiver = !isStaticDeclaration(functionDescriptor) && !isInterface(functionDescriptor.getContainingDeclaration());
|
||||
int reg = hasDispatchReceiver ? 1 : 0;
|
||||
boolean accessorIsConstructor = accessorDescriptor instanceof AccessorForConstructorDescriptor;
|
||||
if (!accessorIsConstructor && functionDescriptor instanceof ConstructorDescriptor) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,12 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.descriptors.impl;
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl;
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorBase;
|
||||
import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorImpl;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
|
||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.annotation.AnnotatedSimple;
|
||||
import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithFakeAnnotations;
|
||||
import org.jetbrains.kotlin.codegen.context.*;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
@@ -57,9 +58,7 @@ import java.util.List;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.getDeprecatedAccessFlag;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.getVisibilityForBackingField;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.isPropertyWithBackingFieldCopyInOuterClass;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConstOrHasJvmFieldAnnotation;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.FIELD_FOR_PROPERTY;
|
||||
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.SYNTHETIC_METHOD_FOR_PROPERTY;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
|
||||
@@ -271,7 +270,7 @@ public class PropertyCodegen {
|
||||
}
|
||||
|
||||
// Annotations on properties are stored in bytecode on an empty synthetic method. This way they're still
|
||||
// accessible via reflection, and 'deprecated' and 'synthetic' flags prevent this method from being called accidentally
|
||||
// accessible via reflection, and 'deprecated' and 'private' flags prevent this method from being called accidentally
|
||||
private void generateSyntheticMethodIfNeeded(@NotNull PropertyDescriptor descriptor, @NotNull Annotations annotations) {
|
||||
if (annotations.getAllAnnotations().isEmpty()) return;
|
||||
|
||||
@@ -279,9 +278,15 @@ public class PropertyCodegen {
|
||||
if (!isInterface(contextDescriptor) ||
|
||||
(FunctionCodegen.processInterface(contextDescriptor, kind, state) ||
|
||||
(kind == OwnerKind.DEFAULT_IMPLS && state.getGenerateDefaultImplsForJvm8()))) {
|
||||
memberCodegen.generateSyntheticAnnotationsMethod(
|
||||
descriptor, getSyntheticMethodSignature(descriptor), annotations, AnnotationUseSiteTarget.PROPERTY
|
||||
);
|
||||
int flags = ACC_DEPRECATED | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC;
|
||||
Method syntheticMethod = getSyntheticMethodSignature(descriptor);
|
||||
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(descriptor), flags, syntheticMethod.getName(),
|
||||
syntheticMethod.getDescriptor(), null, null);
|
||||
AnnotationCodegen.forMethod(mv, memberCodegen, typeMapper)
|
||||
.genAnnotations(new AnnotatedSimple(annotations), Type.VOID_TYPE, AnnotationUseSiteTarget.PROPERTY);
|
||||
mv.visitCode();
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,7 +540,7 @@ public class PropertyCodegen {
|
||||
StackValue.Property receiver = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
|
||||
return invokeDelegatedPropertyConventionMethodWithReceiver(
|
||||
codegen, typeMapper, resolvedCall, indexInPropertyMetadataArray, propertyMetadataArgumentIndex,
|
||||
receiver, propertyDescriptor
|
||||
receiver
|
||||
);
|
||||
}
|
||||
|
||||
@@ -545,12 +550,9 @@ public class PropertyCodegen {
|
||||
@NotNull ResolvedCall<FunctionDescriptor> resolvedCall,
|
||||
final int indexInPropertyMetadataArray,
|
||||
int propertyMetadataArgumentIndex,
|
||||
@Nullable StackValue receiver,
|
||||
@NotNull PropertyDescriptor propertyDescriptor
|
||||
@Nullable StackValue receiver
|
||||
) {
|
||||
final Type owner = JvmAbi.isPropertyWithBackingFieldInOuterClass(propertyDescriptor) ?
|
||||
codegen.getState().getTypeMapper().mapOwner(propertyDescriptor) :
|
||||
getDelegatedPropertyMetadataOwner(codegen, typeMapper);
|
||||
final Type owner = getDelegatedPropertyMetadataOwner(codegen, typeMapper);
|
||||
|
||||
codegen.tempVariables.put(
|
||||
resolvedCall.getCall().getValueArguments().get(propertyMetadataArgumentIndex).asElement(),
|
||||
|
||||
@@ -883,7 +883,7 @@ public abstract class StackValue {
|
||||
newReceiver.put(newReceiver.type, v);
|
||||
callGenerator.processAndPutHiddenParameters(false);
|
||||
|
||||
defaultArgs = generator.generate(valueArguments, valueArguments, call.getResultingDescriptor());
|
||||
defaultArgs = generator.generate(valueArguments, valueArguments);
|
||||
}
|
||||
|
||||
private ArgumentGenerator createArgumentGenerator() {
|
||||
@@ -1596,16 +1596,6 @@ public abstract class StackValue {
|
||||
public void dup(@NotNull InstructionAdapter v, boolean withReceiver) {
|
||||
AsmUtil.dup(v, extensionReceiver.type, dispatchReceiver.type);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StackValue getDispatchReceiver() {
|
||||
return dispatchReceiver;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StackValue getExtensionReceiver() {
|
||||
return extensionReceiver;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class StackValueWithSimpleReceiver extends StackValue {
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.google.common.collect.Lists;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.cfg.TailRecursionKind;
|
||||
import org.jetbrains.kotlin.codegen.context.MethodContext;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||
@@ -66,7 +65,7 @@ public class TailRecursionCodegen {
|
||||
}
|
||||
|
||||
public void generateTailRecursion(ResolvedCall<?> resolvedCall) {
|
||||
CallableDescriptor fd = CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(resolvedCall.getResultingDescriptor());
|
||||
CallableDescriptor fd = resolvedCall.getResultingDescriptor();
|
||||
assert fd instanceof FunctionDescriptor : "Resolved call doesn't refer to the function descriptor: " + fd;
|
||||
CallableMethod callable = (CallableMethod) codegen.resolveToCallable((FunctionDescriptor) fd, false, resolvedCall);
|
||||
|
||||
@@ -74,11 +73,6 @@ public class TailRecursionCodegen {
|
||||
if (arguments == null) {
|
||||
throw new IllegalStateException("Failed to arrange value arguments by index: " + fd);
|
||||
}
|
||||
|
||||
if (((FunctionDescriptor) fd).isSuspend()) {
|
||||
AsmUtil.pop(v, callable.getValueParameters().get(callable.getValueParameters().size() - 1).getAsmType());
|
||||
}
|
||||
|
||||
assignParameterValues(fd, callable, arguments);
|
||||
if (callable.getExtensionReceiverType() != null) {
|
||||
if (resolvedCall.getExtensionReceiver() != fd.getExtensionReceiverParameter().getValue()) {
|
||||
|
||||
@@ -44,7 +44,5 @@ public interface CalculatedClosure {
|
||||
@NotNull
|
||||
List<Pair<String, Type>> getRecordedFields();
|
||||
|
||||
boolean isSuspend();
|
||||
|
||||
boolean isSuspendLambda();
|
||||
boolean isCoroutine();
|
||||
}
|
||||
|
||||
@@ -100,21 +100,10 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
@NotNull CallableDescriptor callableDescriptor,
|
||||
@NotNull Collection<KotlinType> supertypes,
|
||||
@NotNull String name
|
||||
) {
|
||||
return recordClassForCallable(element, callableDescriptor, supertypes, name, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ClassDescriptor recordClassForCallable(
|
||||
@NotNull KtElement element,
|
||||
@NotNull CallableDescriptor callableDescriptor,
|
||||
@NotNull Collection<KotlinType> supertypes,
|
||||
@NotNull String name,
|
||||
@Nullable DeclarationDescriptor customContainer
|
||||
) {
|
||||
String simpleName = name.substring(name.lastIndexOf('/') + 1);
|
||||
ClassDescriptor classDescriptor = new SyntheticClassDescriptorForLambda(
|
||||
customContainer != null ? customContainer : correctContainerForLambda(callableDescriptor, element),
|
||||
correctContainerForLambda(callableDescriptor, element),
|
||||
Name.special("<closure-" + simpleName + ">"),
|
||||
supertypes,
|
||||
element
|
||||
@@ -300,8 +289,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
nameStack.push(name);
|
||||
|
||||
if (CoroutineUtilKt.isSuspendLambda(functionDescriptor)) {
|
||||
closure.setSuspend(true);
|
||||
closure.setSuspendLambda();
|
||||
closure.setCoroutine(true);
|
||||
}
|
||||
|
||||
super.visitLambdaExpression(lambdaExpression);
|
||||
@@ -427,11 +415,9 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
// working around a problem with shallow analysis
|
||||
if (functionDescriptor == null) return;
|
||||
|
||||
String nameForClassOrPackageMember = getNameForClassOrPackageMember(functionDescriptor);
|
||||
|
||||
if (functionDescriptor instanceof SimpleFunctionDescriptor && functionDescriptor.isSuspend()) {
|
||||
SimpleFunctionDescriptor jvmSuspendFunctionView =
|
||||
CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(
|
||||
CoroutineCodegenUtilKt.createJvmSuspendFunctionView(
|
||||
(SimpleFunctionDescriptor) functionDescriptor
|
||||
);
|
||||
|
||||
@@ -451,53 +437,31 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
|
||||
bindingTrace.record(
|
||||
CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW,
|
||||
functionDescriptor,
|
||||
(SimpleFunctionDescriptor) functionDescriptor,
|
||||
jvmSuspendFunctionView
|
||||
);
|
||||
|
||||
if (CoroutineCodegenUtilKt.containsNonTailSuspensionCalls(functionDescriptor, bindingContext)) {
|
||||
if (nameForClassOrPackageMember != null) {
|
||||
nameStack.push(nameForClassOrPackageMember);
|
||||
}
|
||||
|
||||
processNamedFunctionWithClosure(function, functionDescriptor, functionDescriptor).setSuspend(true);
|
||||
|
||||
if (nameForClassOrPackageMember != null) {
|
||||
nameStack.pop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String nameForClassOrPackageMember = getNameForClassOrPackageMember(functionDescriptor);
|
||||
if (nameForClassOrPackageMember != null) {
|
||||
nameStack.push(nameForClassOrPackageMember);
|
||||
super.visitNamedFunction(function);
|
||||
nameStack.pop();
|
||||
}
|
||||
else {
|
||||
processNamedFunctionWithClosure(function, functionDescriptor, null);
|
||||
String name = inventAnonymousClassName();
|
||||
Collection<KotlinType> supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor);
|
||||
ClassDescriptor classDescriptor = recordClassForCallable(function, functionDescriptor, supertypes, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
classStack.push(classDescriptor);
|
||||
nameStack.push(name);
|
||||
super.visitNamedFunction(function);
|
||||
nameStack.pop();
|
||||
classStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
private MutableClosure processNamedFunctionWithClosure(
|
||||
@NotNull KtNamedFunction function,
|
||||
@NotNull FunctionDescriptor functionDescriptor,
|
||||
@Nullable DeclarationDescriptor customContainer
|
||||
) {
|
||||
String name = inventAnonymousClassName();
|
||||
Collection<KotlinType> supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor);
|
||||
ClassDescriptor classDescriptor = recordClassForCallable(function, functionDescriptor, supertypes, name, customContainer);
|
||||
MutableClosure closure = recordClosure(classDescriptor, name);
|
||||
|
||||
classStack.push(classDescriptor);
|
||||
nameStack.push(name);
|
||||
super.visitNamedFunction(function);
|
||||
nameStack.pop();
|
||||
classStack.pop();
|
||||
|
||||
return closure;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String getNameForClassOrPackageMember(@NotNull DeclarationDescriptor descriptor) {
|
||||
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
|
||||
@@ -648,10 +612,8 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
int fieldNumber = mappings.size();
|
||||
|
||||
assert expression.getSubjectExpression() != null : "subject expression should be not null in a valid when by enums";
|
||||
|
||||
KotlinType type = WhenChecker.whenSubjectType(expression, bindingContext);
|
||||
KotlinType type = bindingContext.getType(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";
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ public class CodegenBinding {
|
||||
public static final WritableSlice<VariableDescriptor, VariableDescriptor> LOCAL_VARIABLE_PROPERTY_METADATA =
|
||||
Slices.createSimpleSlice();
|
||||
|
||||
public static final WritableSlice<FunctionDescriptor, FunctionDescriptor> SUSPEND_FUNCTION_TO_JVM_VIEW =
|
||||
public static final WritableSlice<SimpleFunctionDescriptor, SimpleFunctionDescriptor> SUSPEND_FUNCTION_TO_JVM_VIEW =
|
||||
Slices.createSimpleSlice();
|
||||
|
||||
public static final WritableSlice<ValueParameterDescriptor, ValueParameterDescriptor> PARAMETER_SYNONYM =
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.codegen.binding;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.StackValue;
|
||||
import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
@@ -41,8 +40,7 @@ public final class MutableClosure implements CalculatedClosure {
|
||||
private Map<DeclarationDescriptor, Integer> parameterOffsetInConstructor;
|
||||
private List<Pair<String, Type>> recordedFields;
|
||||
private KotlinType captureReceiverType;
|
||||
private boolean isSuspend;
|
||||
private boolean isSuspendLambda;
|
||||
private boolean isCoroutine;
|
||||
|
||||
MutableClosure(@NotNull ClassDescriptor classDescriptor, @Nullable ClassDescriptor enclosingClass) {
|
||||
this.closureClass = classDescriptor;
|
||||
@@ -121,24 +119,15 @@ public final class MutableClosure implements CalculatedClosure {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuspend() {
|
||||
return isSuspend;
|
||||
public boolean isCoroutine() {
|
||||
return isCoroutine;
|
||||
}
|
||||
|
||||
public void setSuspend(boolean suspend) {
|
||||
this.isSuspend = suspend;
|
||||
public void setCoroutine(boolean coroutine) {
|
||||
this.isCoroutine = coroutine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuspendLambda() {
|
||||
return isSuspendLambda;
|
||||
}
|
||||
|
||||
public void setSuspendLambda() {
|
||||
isSuspendLambda = true;
|
||||
}
|
||||
|
||||
private void recordField(String name, Type type) {
|
||||
public void recordField(String name, Type type) {
|
||||
if (recordedFields == null) {
|
||||
recordedFields = new LinkedList<Pair<String, Type>>();
|
||||
}
|
||||
@@ -146,8 +135,6 @@ public final class MutableClosure implements CalculatedClosure {
|
||||
}
|
||||
|
||||
public void captureVariable(EnclosedValueDescriptor value) {
|
||||
recordField(value.getFieldName(), value.getType());
|
||||
|
||||
if (captureVariables == null) {
|
||||
captureVariables = new LinkedHashMap<DeclarationDescriptor, EnclosedValueDescriptor>();
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ private fun Iterable<PackageParts>.addCompiledParts(state: GenerationState): Lis
|
||||
val incrementalCache = state.incrementalCacheForThisTarget ?: return this.toList()
|
||||
val moduleMappingData = incrementalCache.getModuleMappingData() ?: return this.toList()
|
||||
|
||||
val mapping = ModuleMapping.create(moduleMappingData, "<incremental>", state.deserializationConfiguration)
|
||||
val mapping = ModuleMapping.create(moduleMappingData, "<incremental>")
|
||||
|
||||
incrementalCache.getObsoletePackageParts().forEach { internalName ->
|
||||
val qualifier = internalName.substringBeforeLast('/', "").replace('/', '.')
|
||||
|
||||
@@ -21,34 +21,30 @@ import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext
|
||||
import org.jetbrains.kotlin.codegen.context.PackageContext
|
||||
import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics
|
||||
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.Renderers
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.RenderingContext
|
||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.SpecialSignatureInfo
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtObjectDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isSubclass
|
||||
import org.jetbrains.kotlin.resolve.annotations.hasJvmStaticAnnotation
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
|
||||
import org.jetbrains.kotlin.serialization.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -271,27 +267,25 @@ private fun CallableDescriptor.isJvmStaticIn(predicate: (DeclarationDescriptor)
|
||||
fun Collection<VariableDescriptor>.filterOutDescriptorsWithSpecialNames() = filterNot { it.name.isSpecial }
|
||||
|
||||
|
||||
class TypeAndNullability(@JvmField val type: Type, @JvmField val isNullable: Boolean)
|
||||
|
||||
fun calcTypeForIEEE754ArithmeticIfNeeded(expression: KtExpression?, bindingContext: BindingContext, descriptor: DeclarationDescriptor): TypeAndNullability? {
|
||||
fun calcTypeForIEEE754ArithmeticIfNeeded(expression: KtExpression?, bindingContext: BindingContext, descriptor: DeclarationDescriptor): Type? {
|
||||
val ktType = expression.kotlinType(bindingContext) ?: return null
|
||||
|
||||
if (KotlinBuiltIns.isDoubleOrNullableDouble(ktType)) {
|
||||
return TypeAndNullability(Type.DOUBLE_TYPE, TypeUtils.isNullableType(ktType))
|
||||
return Type.DOUBLE_TYPE
|
||||
}
|
||||
|
||||
if (KotlinBuiltIns.isFloatOrNullableFloat(ktType)) {
|
||||
return TypeAndNullability(Type.FLOAT_TYPE, TypeUtils.isNullableType(ktType))
|
||||
return Type.FLOAT_TYPE
|
||||
}
|
||||
|
||||
val dataFlow = DataFlowValueFactory.createDataFlowValue(expression!!, ktType, bindingContext, descriptor)
|
||||
val stableTypes = bindingContext.getDataFlowInfoBefore(expression).getStableTypes(dataFlow)
|
||||
return stableTypes.firstNotNullResult {
|
||||
if (KotlinBuiltIns.isDoubleOrNullableDouble(it)) {
|
||||
TypeAndNullability(Type.DOUBLE_TYPE, TypeUtils.isNullableType(it))
|
||||
Type.DOUBLE_TYPE
|
||||
}
|
||||
else if (KotlinBuiltIns.isFloatOrNullableFloat(it)) {
|
||||
TypeAndNullability(Type.FLOAT_TYPE, TypeUtils.isNullableType(it))
|
||||
Type.FLOAT_TYPE
|
||||
}
|
||||
else {
|
||||
null
|
||||
@@ -345,35 +339,3 @@ fun MemberDescriptor.isToArrayFromCollection(): Boolean {
|
||||
|
||||
return isGenericToArray() || isNonGenericToArray()
|
||||
}
|
||||
|
||||
fun FqName.topLevelClassInternalName() = JvmClassName.byClassId(ClassId(parent(), shortName())).internalName
|
||||
fun FqName.topLevelClassAsmType(): Type = Type.getObjectType(topLevelClassInternalName())
|
||||
|
||||
fun initializeVariablesForDestructuredLambdaParameters(codegen: ExpressionCodegen, valueParameters: List<ValueParameterDescriptor>) {
|
||||
val savedIsShouldMarkLineNumbers = codegen.isShouldMarkLineNumbers
|
||||
// Do not write line numbers until destructuring happens
|
||||
// (otherwise destructuring variables will be uninitialized in the beginning of lambda)
|
||||
codegen.isShouldMarkLineNumbers = false
|
||||
|
||||
for (parameterDescriptor in valueParameters) {
|
||||
if (parameterDescriptor !is ValueParameterDescriptorImpl.WithDestructuringDeclaration) continue
|
||||
|
||||
for (entry in parameterDescriptor.destructuringVariables.filterOutDescriptorsWithSpecialNames()) {
|
||||
codegen.myFrameMap.enter(entry, codegen.typeMapper.mapType(entry.type))
|
||||
}
|
||||
|
||||
val destructuringDeclaration =
|
||||
(DescriptorToSourceUtils.descriptorToDeclaration(parameterDescriptor) as? KtParameter)?.destructuringDeclaration
|
||||
?: error("Destructuring declaration for descriptor $parameterDescriptor not found")
|
||||
|
||||
codegen.initializeDestructuringDeclarationVariables(
|
||||
destructuringDeclaration,
|
||||
TransientReceiver(parameterDescriptor.type),
|
||||
codegen.findLocalOrCapturedValue(parameterDescriptor) ?: error("Local var not found for parameter $parameterDescriptor")
|
||||
)
|
||||
}
|
||||
|
||||
codegen.isShouldMarkLineNumbers = savedIsShouldMarkLineNumbers
|
||||
}
|
||||
|
||||
fun <D : CallableDescriptor> D.unwrapFrontendVersion() = unwrapInitialDescriptorForSuspendFunction()
|
||||
|
||||
@@ -26,23 +26,23 @@ import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.anonymousClass
|
||||
|
||||
public class ClosureContext extends ClassContext {
|
||||
private final FunctionDescriptor functionDescriptor;
|
||||
private final FunctionDescriptor originalSuspendLambdaDescriptor;
|
||||
private final FunctionDescriptor coroutineDescriptor;
|
||||
|
||||
public ClosureContext(
|
||||
@NotNull KotlinTypeMapper typeMapper,
|
||||
@NotNull FunctionDescriptor functionDescriptor,
|
||||
@Nullable CodegenContext parentContext,
|
||||
@NotNull LocalLookup localLookup,
|
||||
// original suspend lambda descriptor
|
||||
@Nullable FunctionDescriptor originalSuspendLambdaDescriptor
|
||||
// original coroutine lambda descriptor having return type T (the type that can be returned within lambda)
|
||||
@Nullable FunctionDescriptor coroutineDescriptor
|
||||
) {
|
||||
super(typeMapper,
|
||||
anonymousClassForCallable(
|
||||
typeMapper.getBindingContext(), originalSuspendLambdaDescriptor != null ? originalSuspendLambdaDescriptor : functionDescriptor),
|
||||
typeMapper.getBindingContext(), coroutineDescriptor != null ? coroutineDescriptor : functionDescriptor),
|
||||
OwnerKind.IMPLEMENTATION, parentContext, localLookup);
|
||||
|
||||
this.functionDescriptor = functionDescriptor;
|
||||
this.originalSuspendLambdaDescriptor = originalSuspendLambdaDescriptor;
|
||||
this.coroutineDescriptor = coroutineDescriptor;
|
||||
}
|
||||
|
||||
public ClosureContext(
|
||||
@@ -65,7 +65,7 @@ public class ClosureContext extends ClassContext {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public FunctionDescriptor getOriginalSuspendLambdaDescriptor() {
|
||||
return originalSuspendLambdaDescriptor;
|
||||
public FunctionDescriptor getCoroutineDescriptor() {
|
||||
return coroutineDescriptor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ import org.jetbrains.org.objectweb.asm.Type;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.getVisibilityAccessFlag;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isNonDefaultInterfaceMember;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
|
||||
import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUtilKt.isInlineOnlyOrReifiable;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PRIVATE;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PROTECTED;
|
||||
@@ -340,14 +340,14 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
|
||||
@NotNull
|
||||
public ClosureContext intoCoroutineClosure(
|
||||
// copy of lambda descriptor that has an additional value parameter Continuation<T>
|
||||
@NotNull FunctionDescriptor jvmViewOfSuspendLambda,
|
||||
// original coroutine lambda descriptor
|
||||
@NotNull FunctionDescriptor originalSuspendLambdaDescriptor,
|
||||
// copy of lambda descriptor that have Continuation<Unit> return type (as it's ep)
|
||||
@NotNull FunctionDescriptor funDescriptorReturningContinuation,
|
||||
// original coroutine lambda descriptor having return type T (the type that can be returned within lambda)
|
||||
@NotNull FunctionDescriptor coroutineLambdaDescriptor,
|
||||
@NotNull LocalLookup localLookup,
|
||||
@NotNull KotlinTypeMapper typeMapper
|
||||
) {
|
||||
return new ClosureContext(typeMapper, jvmViewOfSuspendLambda, this, localLookup, originalSuspendLambdaDescriptor);
|
||||
return new ClosureContext(typeMapper, funDescriptorReturningContinuation, this, localLookup, coroutineLambdaDescriptor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -391,11 +391,8 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@NotNull
|
||||
public <D extends CallableMemberDescriptor> D getAccessorForSuperCallIfNeeded(
|
||||
@NotNull D descriptor,
|
||||
@Nullable ClassDescriptor superCallTarget,
|
||||
@NotNull GenerationState state) {
|
||||
if (superCallTarget != null && !isNonDefaultInterfaceMember(descriptor, state)) {
|
||||
public <D extends CallableMemberDescriptor> D getAccessorForSuperCallIfNeeded(@NotNull D descriptor, @Nullable ClassDescriptor superCallTarget) {
|
||||
if (superCallTarget != null && !isJvmInterface(descriptor.getContainingDeclaration())) {
|
||||
CodegenContext afterInline = getFirstCrossInlineOrNonInlineContext();
|
||||
CodegenContext c = afterInline.findParentContextWithDescriptor(superCallTarget);
|
||||
assert c != null : "Couldn't find a context for a super-call: " + descriptor;
|
||||
|
||||
@@ -75,6 +75,7 @@ public interface LocalLookup {
|
||||
enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, type);
|
||||
}
|
||||
|
||||
closure.recordField(fieldName, type);
|
||||
closure.captureVariable(enclosedValueDescriptor);
|
||||
|
||||
return innerValue;
|
||||
@@ -114,6 +115,7 @@ public interface LocalLookup {
|
||||
StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(localType, classType, fieldName, false,
|
||||
StackValue.LOCAL_0, vd);
|
||||
|
||||
closure.recordField(fieldName, localType);
|
||||
closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType));
|
||||
|
||||
return innerValue;
|
||||
|
||||
@@ -17,21 +17,18 @@
|
||||
package org.jetbrains.kotlin.codegen.coroutines
|
||||
|
||||
import com.intellij.util.ArrayUtil
|
||||
import org.jetbrains.kotlin.backend.common.CONTINUATION_RESUME_METHOD_NAME
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.context.ClosureContext
|
||||
import org.jetbrains.kotlin.codegen.context.MethodContext
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.coroutines.isSuspendLambda
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
import org.jetbrains.kotlin.psi.KtFunctionLiteral
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
@@ -40,39 +37,35 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
|
||||
|
||||
class CoroutineCodegen private constructor(
|
||||
outerExpressionCodegen: ExpressionCodegen,
|
||||
class CoroutineCodegen(
|
||||
state: GenerationState,
|
||||
element: KtElement,
|
||||
private val closureContext: ClosureContext,
|
||||
strategy: FunctionGenerationStrategy,
|
||||
parentCodegen: MemberCodegen<*>,
|
||||
classBuilder: ClassBuilder,
|
||||
private val originalSuspendFunctionDescriptor: FunctionDescriptor,
|
||||
private val isSuspendLambda: Boolean
|
||||
) : ClosureCodegen(
|
||||
outerExpressionCodegen.state,
|
||||
element, null, closureContext, null,
|
||||
FailingFunctionGenerationStrategy,
|
||||
outerExpressionCodegen.parentCodegen, classBuilder
|
||||
) {
|
||||
private val coroutineLambdaDescriptor: FunctionDescriptor
|
||||
) : ClosureCodegen(state, element, null, closureContext, null, strategy, parentCodegen, classBuilder) {
|
||||
|
||||
private val classDescriptor = closureContext.contextDescriptor
|
||||
private val builtIns = funDescriptor.builtIns
|
||||
|
||||
private lateinit var constructorToUseFromInvoke: Method
|
||||
|
||||
// protected fun doResume(result, throwable)
|
||||
private val doResumeDescriptor =
|
||||
SimpleFunctionDescriptorImpl.create(
|
||||
classDescriptor, Annotations.EMPTY, Name.identifier(DO_RESUME_METHOD_NAME), CallableMemberDescriptor.Kind.DECLARATION,
|
||||
classDescriptor, Annotations.EMPTY, Name.identifier("doResume"), CallableMemberDescriptor.Kind.DECLARATION,
|
||||
funDescriptor.source
|
||||
).apply doResume@{
|
||||
initialize(
|
||||
@@ -82,39 +75,40 @@ class CoroutineCodegen private constructor(
|
||||
listOf(
|
||||
ValueParameterDescriptorImpl(
|
||||
this@doResume, null, 0, Annotations.EMPTY, Name.identifier("data"),
|
||||
builtIns.nullableAnyType,
|
||||
module.builtIns.nullableAnyType,
|
||||
/* isDefault = */ false, /* isCrossinline = */ false,
|
||||
/* isNoinline = */ false,
|
||||
/* varargElementType = */ null, SourceElement.NO_SOURCE
|
||||
),
|
||||
ValueParameterDescriptorImpl(
|
||||
this@doResume, null, 1, Annotations.EMPTY, Name.identifier("throwable"),
|
||||
builtIns.throwable.defaultType.makeNullable(),
|
||||
module.builtIns.throwable.defaultType.makeNullable(),
|
||||
/* isDefault = */ false, /* isCrossinline = */ false,
|
||||
/* isNoinline = */ false,
|
||||
/* varargElementType = */ null, SourceElement.NO_SOURCE
|
||||
)
|
||||
),
|
||||
builtIns.nullableAnyType,
|
||||
funDescriptor.builtIns.nullableAnyType,
|
||||
Modality.FINAL,
|
||||
Visibilities.PUBLIC,
|
||||
mapOf(INITIAL_SUSPEND_DESCRIPTOR_FOR_DO_RESUME to originalSuspendFunctionDescriptor)
|
||||
Visibilities.PROTECTED
|
||||
)
|
||||
}
|
||||
|
||||
private val createCoroutineDescriptor =
|
||||
funDescriptor.createCustomCopy {
|
||||
setName(Name.identifier(SUSPEND_FUNCTION_CREATE_METHOD_NAME))
|
||||
setName(Name.identifier("create"))
|
||||
setReturnType(
|
||||
funDescriptor.module.getContinuationOfTypeOrAny(builtIns.unitType)
|
||||
KotlinTypeFactory.simpleNotNullType(
|
||||
Annotations.EMPTY,
|
||||
funDescriptor.builtIns.continuationClassDescriptor,
|
||||
listOf(funDescriptor.builtIns.unitType.asTypeProjection())
|
||||
)
|
||||
)
|
||||
// 'create' method should not inherit initial descriptor for suspend function from original descriptor
|
||||
putUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION, null)
|
||||
setVisibility(Visibilities.PUBLIC)
|
||||
}
|
||||
|
||||
override fun generateClosureBody() {
|
||||
for (parameter in allFunctionParameters()) {
|
||||
for (parameter in allLambdaParameters()) {
|
||||
val fieldInfo = parameter.getFieldInfoForCoroutineLambdaParameter()
|
||||
v.newField(
|
||||
OtherOrigin(parameter),
|
||||
@@ -127,17 +121,9 @@ class CoroutineCodegen private constructor(
|
||||
generateDoResume()
|
||||
}
|
||||
|
||||
override fun generateBridges() {
|
||||
if (!isSuspendLambda) return
|
||||
super.generateBridges()
|
||||
}
|
||||
|
||||
override fun generateBody() {
|
||||
super.generateBody()
|
||||
|
||||
if (!isSuspendLambda) return
|
||||
|
||||
// create() = ...
|
||||
functionCodegen.generateMethod(JvmDeclarationOrigin.NO_ORIGIN, createCoroutineDescriptor,
|
||||
object : FunctionGenerationStrategy.CodegenBased(state) {
|
||||
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
|
||||
@@ -153,7 +139,7 @@ class CoroutineCodegen private constructor(
|
||||
}
|
||||
})
|
||||
|
||||
if (allFunctionParameters().size <= 1) {
|
||||
if (allLambdaParameters().size <= 1) {
|
||||
val delegate = typeMapper.mapSignatureSkipGeneric(createCoroutineDescriptor).asmMethod
|
||||
|
||||
val bridgeParameters = (1..delegate.argumentTypes.size - 1).map { AsmTypes.OBJECT_TYPE } + delegate.argumentTypes.last()
|
||||
@@ -176,21 +162,30 @@ class CoroutineCodegen private constructor(
|
||||
v.thisName,
|
||||
createCoroutineDescriptor.name.identifier,
|
||||
Type.getMethodDescriptor(
|
||||
CONTINUATION_ASM_TYPE,
|
||||
AsmTypes.CONTINUATION,
|
||||
*parameterTypes.toTypedArray()
|
||||
),
|
||||
false
|
||||
)
|
||||
checkcast(Type.getObjectType(v.thisName))
|
||||
|
||||
// .doResume(Unit)
|
||||
invokeDoResumeWithUnit(v.thisName)
|
||||
// .resume(Unit)
|
||||
StackValue.putUnitInstance(this)
|
||||
invokevirtual(
|
||||
AsmTypes.RESTRICTED_COROUTINE_IMPL.internalName,
|
||||
CONTINUATION_RESUME_METHOD_NAME.identifier,
|
||||
Type.getMethodDescriptor(Type.VOID_TYPE, AsmTypes.OBJECT_TYPE),
|
||||
false
|
||||
)
|
||||
|
||||
loadSuspendMarker()
|
||||
areturn(AsmTypes.OBJECT_TYPE)
|
||||
}
|
||||
|
||||
|
||||
override fun generateConstructor(): Method {
|
||||
val args = calculateConstructorParameters(typeMapper, closure, asmType)
|
||||
val argTypes = args.map { it.fieldType }.plus(CONTINUATION_ASM_TYPE).toTypedArray()
|
||||
val argTypes = args.map { it.fieldType }.plus(AsmTypes.CONTINUATION).toTypedArray()
|
||||
|
||||
val constructor = Method("<init>", Type.VOID_TYPE, argTypes)
|
||||
val mv = v.newMethod(
|
||||
@@ -210,7 +205,7 @@ class CoroutineCodegen private constructor(
|
||||
iv.iconst(calculateArity())
|
||||
iv.load(argTypes.map { it.size }.sum(), AsmTypes.OBJECT_TYPE)
|
||||
|
||||
val superClassConstructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE, CONTINUATION_ASM_TYPE)
|
||||
val superClassConstructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE, AsmTypes.CONTINUATION)
|
||||
iv.invokespecial(superClassAsmType.internalName, "<init>", superClassConstructorDescriptor, false)
|
||||
|
||||
iv.visitInsn(Opcodes.RETURN)
|
||||
@@ -222,7 +217,6 @@ class CoroutineCodegen private constructor(
|
||||
}
|
||||
|
||||
private fun generateCreateCoroutineMethod(codegen: ExpressionCodegen) {
|
||||
assert(isSuspendLambda) { "create method should only be generated for suspend lambdas" }
|
||||
val classDescriptor = closureContext.contextDescriptor
|
||||
val owner = typeMapper.mapClass(classDescriptor)
|
||||
|
||||
@@ -239,7 +233,7 @@ class CoroutineCodegen private constructor(
|
||||
}
|
||||
|
||||
// load resultContinuation
|
||||
load(allFunctionParameters().map { typeMapper.mapType(it.type).size }.sum() + 1, AsmTypes.OBJECT_TYPE)
|
||||
load(allLambdaParameters().map { typeMapper.mapType(it.type).size }.sum() + 1, AsmTypes.OBJECT_TYPE)
|
||||
|
||||
invokespecial(owner.internalName, constructorToUseFromInvoke.name, constructorToUseFromInvoke.descriptor, false)
|
||||
|
||||
@@ -248,7 +242,7 @@ class CoroutineCodegen private constructor(
|
||||
|
||||
// Pass lambda parameters to 'invoke' call on newly constructed object
|
||||
var index = 1
|
||||
for (parameter in allFunctionParameters()) {
|
||||
for (parameter in allLambdaParameters()) {
|
||||
val fieldInfoForCoroutineLambdaParameter = parameter.getFieldInfoForCoroutineLambdaParameter()
|
||||
load(index, fieldInfoForCoroutineLambdaParameter.fieldType)
|
||||
AsmUtil.genAssignInstanceFieldFromParam(fieldInfoForCoroutineLambdaParameter, index, this, cloneIndex)
|
||||
@@ -261,36 +255,21 @@ class CoroutineCodegen private constructor(
|
||||
}
|
||||
|
||||
private fun ExpressionCodegen.initializeCoroutineParameters() {
|
||||
if (!isSuspendLambda && !originalSuspendFunctionDescriptor.isTailrec) return
|
||||
for (parameter in allFunctionParameters()) {
|
||||
val fieldStackValue =
|
||||
if (isSuspendLambda)
|
||||
StackValue.field(
|
||||
parameter.getFieldInfoForCoroutineLambdaParameter(), generateThisOrOuter(context.thisDescriptor, false)
|
||||
)
|
||||
else
|
||||
closureContext.lookupInContext(parameter, null, state, /* ignoreNoOuter = */ false)
|
||||
|
||||
for (parameter in allLambdaParameters()) {
|
||||
val mappedType = typeMapper.mapType(parameter.type)
|
||||
fieldStackValue.put(mappedType, v)
|
||||
|
||||
val newIndex = myFrameMap.enter(parameter, mappedType)
|
||||
|
||||
generateLoadField(parameter.getFieldInfoForCoroutineLambdaParameter())
|
||||
v.store(newIndex, mappedType)
|
||||
}
|
||||
|
||||
// necessary for proper tailrec codegen
|
||||
val actualMethodStartLabel = Label()
|
||||
v.visitLabel(actualMethodStartLabel)
|
||||
context.setMethodStartLabel(actualMethodStartLabel)
|
||||
|
||||
if (isSuspendLambda) {
|
||||
initializeVariablesForDestructuredLambdaParameters(this, originalSuspendFunctionDescriptor.valueParameters)
|
||||
}
|
||||
}
|
||||
|
||||
private fun allFunctionParameters() =
|
||||
originalSuspendFunctionDescriptor.extensionReceiverParameter.singletonOrEmptyList() +
|
||||
originalSuspendFunctionDescriptor.valueParameters.orEmpty()
|
||||
private fun allLambdaParameters() =
|
||||
coroutineLambdaDescriptor.extensionReceiverParameter.singletonOrEmptyList() + coroutineLambdaDescriptor.valueParameters
|
||||
|
||||
private fun ExpressionCodegen.generateLoadField(fieldInfo: FieldInfo) {
|
||||
StackValue.field(fieldInfo, generateThisOrOuter(context.thisDescriptor, false)).put(fieldInfo.fieldType, v)
|
||||
}
|
||||
|
||||
private fun ParameterDescriptor.getFieldInfoForCoroutineLambdaParameter() =
|
||||
createHiddenFieldInfo(type, COROUTINE_LAMBDA_PARAMETER_PREFIX + (this.safeAs<ValueParameterDescriptor>()?.index ?: ""))
|
||||
@@ -316,81 +295,33 @@ class CoroutineCodegen private constructor(
|
||||
)
|
||||
}
|
||||
|
||||
override fun generateKotlinMetadataAnnotation() {
|
||||
if (isSuspendLambda) {
|
||||
super.generateKotlinMetadataAnnotation()
|
||||
}
|
||||
else {
|
||||
writeKotlinMetadata(v, state, KotlinClassHeader.Kind.SYNTHETIC_CLASS, 0) {
|
||||
// Do not write method metadata for raw coroutine state machines
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun shouldCreateByLambda(
|
||||
originalSuspendLambdaDescriptor: CallableDescriptor,
|
||||
declaration: KtElement): Boolean {
|
||||
return (declaration is KtFunctionLiteral && originalSuspendLambdaDescriptor.isSuspendLambda)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun createByLambda(
|
||||
fun create(
|
||||
expressionCodegen: ExpressionCodegen,
|
||||
originalSuspendLambdaDescriptor: FunctionDescriptor,
|
||||
originalCoroutineLambdaDescriptor: FunctionDescriptor,
|
||||
declaration: KtElement,
|
||||
classBuilder: ClassBuilder
|
||||
): ClosureCodegen? {
|
||||
if (!shouldCreateByLambda(originalSuspendLambdaDescriptor, declaration)) return null
|
||||
if (declaration !is KtFunctionLiteral) return null
|
||||
if (!originalCoroutineLambdaDescriptor.isSuspendLambda) return null
|
||||
|
||||
val descriptorWithContinuationReturnType = createJvmSuspendFunctionView(originalCoroutineLambdaDescriptor)
|
||||
|
||||
val state = expressionCodegen.state
|
||||
return CoroutineCodegen(
|
||||
expressionCodegen,
|
||||
state,
|
||||
declaration,
|
||||
expressionCodegen.context.intoCoroutineClosure(
|
||||
getOrCreateJvmSuspendFunctionView(originalSuspendLambdaDescriptor, expressionCodegen.state.bindingContext),
|
||||
originalSuspendLambdaDescriptor, expressionCodegen, expressionCodegen.state.typeMapper
|
||||
descriptorWithContinuationReturnType, originalCoroutineLambdaDescriptor, expressionCodegen, state.typeMapper
|
||||
),
|
||||
classBuilder,
|
||||
originalSuspendLambdaDescriptor,
|
||||
isSuspendLambda = true
|
||||
)
|
||||
}
|
||||
|
||||
fun create(
|
||||
expressionCodegen: ExpressionCodegen,
|
||||
originalSuspendDescriptor: FunctionDescriptor,
|
||||
declaration: KtFunction,
|
||||
state: GenerationState
|
||||
): CoroutineCodegen {
|
||||
val cv = state.factory.newVisitor(
|
||||
OtherOrigin(declaration, originalSuspendDescriptor),
|
||||
CodegenBinding.asmTypeForAnonymousClass(state.bindingContext, originalSuspendDescriptor),
|
||||
declaration.containingFile
|
||||
)
|
||||
|
||||
return CoroutineCodegen(
|
||||
expressionCodegen, declaration,
|
||||
expressionCodegen.context.intoClosure(
|
||||
originalSuspendDescriptor, expressionCodegen, expressionCodegen.state.typeMapper
|
||||
),
|
||||
cv,
|
||||
originalSuspendDescriptor,
|
||||
isSuspendLambda = false
|
||||
FunctionGenerationStrategy.FunctionDefault(state, declaration),
|
||||
expressionCodegen.parentCodegen, classBuilder,
|
||||
originalCoroutineLambdaDescriptor
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val COROUTINE_LAMBDA_PARAMETER_PREFIX = "p$"
|
||||
|
||||
private object FailingFunctionGenerationStrategy : FunctionGenerationStrategy() {
|
||||
override fun generateBody(
|
||||
mv: MethodVisitor,
|
||||
frameMap: FrameMap,
|
||||
signature: JvmMethodSignature,
|
||||
context: MethodContext,
|
||||
parentCodegen: MemberCodegen<*>
|
||||
) {
|
||||
error("This functions must not be called")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,10 @@ class CoroutineTransformerMethodVisitor(
|
||||
|
||||
// Remove unreachable suspension points
|
||||
// If we don't do this, then relevant frames will not be analyzed, that is unexpected from point of view of next steps (e.g. variable spilling)
|
||||
removeUnreachableSuspensionPointsAndExitPoints(methodNode, suspensionPoints)
|
||||
DeadCodeEliminationMethodTransformer().transform(classBuilder.thisName, methodNode)
|
||||
suspensionPoints.removeAll {
|
||||
it.suspensionCallBegin.next == null && it.suspensionCallBegin.previous == null
|
||||
}
|
||||
|
||||
processUninitializedStores(methodNode)
|
||||
|
||||
@@ -102,12 +105,12 @@ class CoroutineTransformerMethodVisitor(
|
||||
// tableswitch(this.label)
|
||||
insertBefore(firstToInsertBefore,
|
||||
insnListOf(
|
||||
*withInstructionAdapter { loadCoroutineSuspendedMarker() }.toArray(),
|
||||
*withInstructionAdapter { loadSuspendMarker() }.toArray(),
|
||||
VarInsnNode(Opcodes.ASTORE, suspendMarkerVarIndex),
|
||||
VarInsnNode(Opcodes.ALOAD, 0),
|
||||
FieldInsnNode(
|
||||
Opcodes.GETFIELD,
|
||||
COROUTINE_IMPL_ASM_TYPE.internalName,
|
||||
AsmTypes.RESTRICTED_COROUTINE_IMPL.internalName,
|
||||
COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor
|
||||
),
|
||||
TableSwitchInsnNode(0,
|
||||
@@ -133,22 +136,6 @@ class CoroutineTransformerMethodVisitor(
|
||||
|
||||
}
|
||||
|
||||
private fun removeUnreachableSuspensionPointsAndExitPoints(methodNode: MethodNode, suspensionPoints: MutableList<SuspensionPoint>) {
|
||||
val dceResult = DeadCodeEliminationMethodTransformer().transformWithResult(classBuilder.thisName, methodNode)
|
||||
|
||||
// If the suspension call begin is alive and suspension call end is dead
|
||||
// (e.g., an inlined suspend function call ends with throwing a exception -- see KT-15017),
|
||||
// this is an exit point for the corresponding coroutine.
|
||||
// It doesn't introduce an additional state to the corresponding coroutine's FSM.
|
||||
suspensionPoints.forEach {
|
||||
if (dceResult.isAlive(it.suspensionCallBegin) && dceResult.isRemoved(it.suspensionCallEnd)) {
|
||||
methodNode.instructions.remove(it.suspensionCallBegin)
|
||||
}
|
||||
}
|
||||
|
||||
suspensionPoints.removeAll { dceResult.isRemoved(it.suspensionCallBegin) || dceResult.isRemoved(it.suspensionCallEnd) }
|
||||
}
|
||||
|
||||
private fun collectSuspensionPoints(methodNode: MethodNode): MutableList<SuspensionPoint> {
|
||||
val suspensionPoints = mutableListOf<SuspensionPoint>()
|
||||
val beforeSuspensionPointMarkerStack = Stack<MethodInsnNode>()
|
||||
@@ -162,7 +149,12 @@ class CoroutineTransformerMethodVisitor(
|
||||
}
|
||||
|
||||
AFTER_SUSPENSION_POINT_MARKER_NAME -> {
|
||||
suspensionPoints.add(SuspensionPoint(beforeSuspensionPointMarkerStack.pop(), methodInsn))
|
||||
suspensionPoints.add(
|
||||
SuspensionPoint(
|
||||
suspensionCallBegin = beforeSuspensionPointMarkerStack.pop(),
|
||||
suspensionCallEnd = methodInsn
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,8 +186,8 @@ class CoroutineTransformerMethodVisitor(
|
||||
|
||||
for (suspension in suspensionPoints) {
|
||||
val suspensionCallBegin = suspension.suspensionCallBegin
|
||||
|
||||
assert(frames[suspension.suspensionCallEnd.next.index()]?.stackSize == 1) {
|
||||
val suspensionCallEnd = suspension.suspensionCallEnd
|
||||
assert(frames[suspensionCallEnd.next.index()]?.stackSize == 1) {
|
||||
"Stack should be spilled before suspension call"
|
||||
}
|
||||
|
||||
@@ -229,18 +221,6 @@ class CoroutineTransformerMethodVisitor(
|
||||
}
|
||||
|
||||
for ((index, basicValue) in variablesToSpill) {
|
||||
if (basicValue === StrictBasicValue.NULL_VALUE) {
|
||||
postponedActions.add {
|
||||
with(instructions) {
|
||||
insert(suspension.tryCatchBlockEndLabelAfterSuspensionCall, withInstructionAdapter {
|
||||
aconst(null)
|
||||
store(index, AsmTypes.OBJECT_TYPE)
|
||||
})
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
val type = basicValue.type
|
||||
val normalizedType = type.normalize()
|
||||
|
||||
@@ -315,7 +295,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
VarInsnNode(Opcodes.ALOAD, 0),
|
||||
*withInstructionAdapter { iconst(id) }.toArray(),
|
||||
FieldInsnNode(
|
||||
Opcodes.PUTFIELD, COROUTINE_IMPL_ASM_TYPE.internalName, COROUTINE_LABEL_FIELD_NAME,
|
||||
Opcodes.PUTFIELD, AsmTypes.RESTRICTED_COROUTINE_IMPL.internalName, COROUTINE_LABEL_FIELD_NAME,
|
||||
Type.INT_TYPE.descriptor
|
||||
)
|
||||
)
|
||||
@@ -450,3 +430,9 @@ private class SuspensionPoint(
|
||||
) {
|
||||
lateinit var tryCatchBlocksContinuationLabel: LabelNode
|
||||
}
|
||||
|
||||
private val DEFAULT_VALUE_OPCODES =
|
||||
setOf(Opcodes.ICONST_0, Opcodes.LCONST_0, Opcodes.FCONST_0, Opcodes.DCONST_0, Opcodes.ACONST_NULL,
|
||||
// GETSTATIC Unit.Instance
|
||||
Opcodes.GETSTATIC)
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.coroutines
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.FunctionGenerationStrategy
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
|
||||
class SuspendFunctionGenerationStrategy(
|
||||
state: GenerationState,
|
||||
private val originalSuspendDescriptor: FunctionDescriptor,
|
||||
private val declaration: KtFunction
|
||||
) : FunctionGenerationStrategy.CodegenBased(state) {
|
||||
|
||||
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
|
||||
if (!originalSuspendDescriptor.containsNonTailSuspensionCalls(state.bindingContext)) {
|
||||
return codegen.returnExpression(declaration.bodyExpression)
|
||||
}
|
||||
|
||||
val coroutineCodegen = CoroutineCodegen.create(codegen, originalSuspendDescriptor, declaration, state)
|
||||
coroutineCodegen.generate()
|
||||
|
||||
codegen.putClosureInstanceOnStack(coroutineCodegen, null).put(Type.getObjectType(coroutineCodegen.className), codegen.v)
|
||||
|
||||
with(codegen.v) {
|
||||
invokeDoResumeWithUnit(coroutineCodegen.v.thisName)
|
||||
|
||||
codegen.markLineNumber(declaration, true)
|
||||
|
||||
areturn(AsmTypes.OBJECT_TYPE)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,31 +17,27 @@
|
||||
package org.jetbrains.kotlin.codegen.coroutines
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.backend.common.COROUTINES_INTRINSICS_PACKAGE_FQ_NAME
|
||||
import org.jetbrains.kotlin.backend.common.COROUTINE_SUSPENDED_NAME
|
||||
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineOrReturn
|
||||
import org.jetbrains.kotlin.backend.common.SUSPEND_WITH_CURRENT_CONTINUATION_NAME
|
||||
import org.jetbrains.kotlin.backend.common.getBuiltInSuspendWithCurrentContinuation
|
||||
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.codegen.topLevelClassAsmType
|
||||
import org.jetbrains.kotlin.codegen.topLevelClassInternalName
|
||||
import org.jetbrains.kotlin.coroutines.isSuspendLambda
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTraceContext
|
||||
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.DescriptorEquivalenceForOverrides
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
||||
import org.jetbrains.kotlin.types.TypeConstructorSubstitution
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
@@ -61,35 +57,11 @@ const val AFTER_SUSPENSION_POINT_MARKER_NAME = "afterSuspensionPoint"
|
||||
const val ACTUAL_COROUTINE_START_MARKER_NAME = "actualCoroutineStart"
|
||||
|
||||
const val COROUTINE_LABEL_FIELD_NAME = "label"
|
||||
const val SUSPEND_FUNCTION_CREATE_METHOD_NAME = "create"
|
||||
const val DO_RESUME_METHOD_NAME = "doResume"
|
||||
|
||||
@JvmField
|
||||
val COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME =
|
||||
DescriptorUtils.COROUTINES_PACKAGE_FQ_NAME.child(Name.identifier("jvm")).child(Name.identifier("internal"))
|
||||
|
||||
@JvmField
|
||||
val CONTINUATION_ASM_TYPE = DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME.topLevelClassAsmType()
|
||||
|
||||
@JvmField
|
||||
val COROUTINE_IMPL_ASM_TYPE = COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(Name.identifier("CoroutineImpl")).topLevelClassAsmType()
|
||||
|
||||
private val COROUTINES_INTRINSICS_FILE_FACADE_INTERNAL_NAME =
|
||||
COROUTINES_INTRINSICS_PACKAGE_FQ_NAME.child(Name.identifier("IntrinsicsKt")).topLevelClassAsmType()
|
||||
|
||||
private val INTERNAL_COROUTINE_INTRINSICS_OWNER_INTERNAL_NAME =
|
||||
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(Name.identifier("CoroutineIntrinsics")).topLevelClassInternalName()
|
||||
|
||||
private val NORMALIZE_CONTINUATION_METHOD_NAME = "normalizeContinuation"
|
||||
|
||||
data class ResolvedCallWithRealDescriptor(val resolvedCall: ResolvedCall<*>, val fakeContinuationExpression: KtExpression)
|
||||
|
||||
@JvmField
|
||||
val INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION = object : FunctionDescriptor.UserDataKey<FunctionDescriptor> {}
|
||||
|
||||
@JvmField
|
||||
val INITIAL_SUSPEND_DESCRIPTOR_FOR_DO_RESUME = object : FunctionDescriptor.UserDataKey<FunctionDescriptor> {}
|
||||
|
||||
// Resolved calls to suspension function contain descriptors as they visible within coroutines:
|
||||
// E.g. `fun <V> await(f: CompletableFuture<V>): V` instead of `fun <V> await(f: CompletableFuture<V>, machine: Continuation<V>): Unit`
|
||||
// See `createJvmSuspendFunctionView` and it's usages for clarification
|
||||
@@ -113,18 +85,12 @@ fun ResolvedCall<*>.replaceSuspensionFunctionWithRealDescriptor(
|
||||
)
|
||||
)
|
||||
}
|
||||
val function = candidateDescriptor as? FunctionDescriptor ?: return null
|
||||
val function = candidateDescriptor as? SimpleFunctionDescriptor ?: return null
|
||||
if (!function.isSuspend || function.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) != null) return null
|
||||
|
||||
val newCandidateDescriptor =
|
||||
when (function) {
|
||||
is FunctionImportedFromObject ->
|
||||
getOrCreateJvmSuspendFunctionView(function.callableFromObject, bindingContext).asImportedFromObject()
|
||||
is SimpleFunctionDescriptor ->
|
||||
getOrCreateJvmSuspendFunctionView(function, bindingContext)
|
||||
else ->
|
||||
throw AssertionError("Unexpected suspend function descriptor: $function")
|
||||
}
|
||||
bindingContext.get(CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, function)
|
||||
?: createJvmSuspendFunctionView(function)
|
||||
|
||||
val newCall = ResolvedCallImpl(
|
||||
call,
|
||||
@@ -154,36 +120,13 @@ fun ResolvedCall<*>.replaceSuspensionFunctionWithRealDescriptor(
|
||||
return ResolvedCallWithRealDescriptor(newCall, thisExpression)
|
||||
}
|
||||
|
||||
fun ResolvedCall<*>.isSuspensionPointInStateMachine(bindingContext: BindingContext): Boolean {
|
||||
if (resultingDescriptor.safeAs<FunctionDescriptor>()?.isSuspend != true) return false
|
||||
val enclosingSuspendFunction = bindingContext[BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, call] ?: return false
|
||||
|
||||
return enclosingSuspendFunction.isStateMachineNeeded(bindingContext)
|
||||
}
|
||||
|
||||
fun FunctionDescriptor.isStateMachineNeeded(bindingContext: BindingContext) =
|
||||
isSuspendLambda || containsNonTailSuspensionCalls(bindingContext)
|
||||
|
||||
fun FunctionDescriptor.containsNonTailSuspensionCalls(bindingContext: BindingContext) =
|
||||
bindingContext[BindingContext.CONTAINS_NON_TAIL_SUSPEND_CALLS, original] == true
|
||||
|
||||
fun CallableDescriptor.isSuspendFunctionNotSuspensionView(): Boolean {
|
||||
if (this !is FunctionDescriptor) return false
|
||||
return this.isSuspend && this.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) == null
|
||||
}
|
||||
fun ResolvedCall<*>.isSuspensionPoint(bindingContext: BindingContext) =
|
||||
bindingContext[BindingContext.ENCLOSING_SUSPEND_LAMBDA_FOR_SUSPENSION_POINT, call] != null
|
||||
|
||||
// Suspend functions have irregular signatures on JVM, containing an additional last parameter with type `Continuation<return-type>`,
|
||||
// and return type Any?
|
||||
// This function returns a function descriptor reflecting how the suspend function looks from point of view of JVM
|
||||
@JvmOverloads
|
||||
fun <D : FunctionDescriptor> getOrCreateJvmSuspendFunctionView(function: D, bindingContext: BindingContext? = null): D {
|
||||
assert(function.isSuspend) {
|
||||
"Suspended function is expected, but $function was found"
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
bindingContext?.get(CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, function)?.let { return it as D }
|
||||
|
||||
fun <D : FunctionDescriptor> createJvmSuspendFunctionView(function: D): D {
|
||||
val continuationParameter = ValueParameterDescriptorImpl(
|
||||
function, null, function.valueParameters.size, Annotations.EMPTY, Name.identifier("\$continuation"),
|
||||
// Add j.l.Object to invoke(), because that is the type of parameters we have in FunctionN+1
|
||||
@@ -227,26 +170,27 @@ fun <D : FunctionDescriptor> D.createCustomCopy(
|
||||
}
|
||||
|
||||
private fun FunctionDescriptor.getContinuationParameterTypeOfSuspendFunction() =
|
||||
module.getContinuationOfTypeOrAny(returnType!!)
|
||||
KotlinTypeFactory.simpleType(
|
||||
builtIns.continuationClassDescriptor.defaultType,
|
||||
arguments = listOf(returnType!!.asTypeProjection())
|
||||
)
|
||||
|
||||
fun ModuleDescriptor.getContinuationOfTypeOrAny(kotlinType: KotlinType) =
|
||||
module.findContinuationClassDescriptorOrNull(NoLookupLocation.FROM_BACKEND)?.defaultType?.let {
|
||||
KotlinTypeFactory.simpleType(
|
||||
it,
|
||||
arguments = listOf(kotlinType.asTypeProjection())
|
||||
)
|
||||
} ?: module.builtIns.nullableAnyType
|
||||
fun FunctionDescriptor.isBuiltInSuspendWithCurrentContinuation(): Boolean {
|
||||
if (name != SUSPEND_WITH_CURRENT_CONTINUATION_NAME) return false
|
||||
|
||||
val originalDeclaration = getBuiltInSuspendWithCurrentContinuation() ?: return false
|
||||
|
||||
fun FunctionDescriptor.isBuiltInSuspendCoroutineOrReturnInJvm() =
|
||||
getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION)?.isBuiltInSuspendCoroutineOrReturn() == true
|
||||
return DescriptorEquivalenceForOverrides.areEquivalent(
|
||||
originalDeclaration, this.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION)
|
||||
)
|
||||
}
|
||||
|
||||
fun createMethodNodeForSuspendCoroutineOrReturn(
|
||||
fun createMethodNodeForSuspendWithCurrentContinuation(
|
||||
functionDescriptor: FunctionDescriptor,
|
||||
typeMapper: KotlinTypeMapper
|
||||
): MethodNode {
|
||||
assert(functionDescriptor.isBuiltInSuspendCoroutineOrReturnInJvm()) {
|
||||
"functionDescriptor must be kotlin.coroutines.intrinsics.suspendOrReturn"
|
||||
assert(functionDescriptor.isBuiltInSuspendWithCurrentContinuation()) {
|
||||
"functionDescriptor must be kotlin.coroutines.suspendWithCurrentContinuation"
|
||||
}
|
||||
|
||||
val node =
|
||||
@@ -259,15 +203,6 @@ fun createMethodNodeForSuspendCoroutineOrReturn(
|
||||
|
||||
node.visitVarInsn(Opcodes.ALOAD, 0)
|
||||
node.visitVarInsn(Opcodes.ALOAD, 1)
|
||||
|
||||
node.visitMethodInsn(
|
||||
Opcodes.INVOKESTATIC,
|
||||
INTERNAL_COROUTINE_INTRINSICS_OWNER_INTERNAL_NAME,
|
||||
NORMALIZE_CONTINUATION_METHOD_NAME,
|
||||
Type.getMethodDescriptor(CONTINUATION_ASM_TYPE, CONTINUATION_ASM_TYPE),
|
||||
false
|
||||
)
|
||||
|
||||
node.visitMethodInsn(
|
||||
Opcodes.INVOKEINTERFACE,
|
||||
typeMapper.mapType(functionDescriptor.valueParameters[0]).internalName,
|
||||
@@ -281,29 +216,17 @@ fun createMethodNodeForSuspendCoroutineOrReturn(
|
||||
return node
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <D : CallableDescriptor?> D.unwrapInitialDescriptorForSuspendFunction(): D =
|
||||
this.safeAs<SimpleFunctionDescriptor>()?.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) as D ?: this
|
||||
fun CallableDescriptor?.unwrapInitialDescriptorForSuspendFunction() =
|
||||
(this as? SimpleFunctionDescriptor)?.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) ?: this
|
||||
|
||||
fun InstructionAdapter.loadCoroutineSuspendedMarker() {
|
||||
invokestatic(
|
||||
COROUTINES_INTRINSICS_FILE_FACADE_INTERNAL_NAME.internalName,
|
||||
"get$COROUTINE_SUSPENDED_NAME",
|
||||
fun InstructionAdapter.loadSuspendMarker() {
|
||||
getstatic(
|
||||
AsmTypes.COROUTINES_INTRINSICS.internalName, JvmAbi.INSTANCE_FIELD, AsmTypes.COROUTINES_INTRINSICS.descriptor
|
||||
)
|
||||
invokevirtual(
|
||||
AsmTypes.COROUTINES_INTRINSICS.internalName,
|
||||
"getSUSPENDED",
|
||||
Type.getMethodDescriptor(AsmTypes.OBJECT_TYPE),
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
fun InstructionAdapter.invokeDoResumeWithUnit(thisName: String) {
|
||||
// .doResume(Unit, null)
|
||||
StackValue.putUnitInstance(this)
|
||||
|
||||
aconst(null)
|
||||
|
||||
invokevirtual(
|
||||
thisName,
|
||||
DO_RESUME_METHOD_NAME,
|
||||
Type.getMethodDescriptor(AsmTypes.OBJECT_TYPE, AsmTypes.OBJECT_TYPE, AsmTypes.JAVA_THROWABLE_TYPE),
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ private class UninitializedNewValueMarkerInterpreter : OptimizationBasicInterpre
|
||||
val uninitializedValuesToCopyUsages = hashMapOf<AbstractInsnNode, MutableSet<AbstractInsnNode>>()
|
||||
override fun newOperation(insn: AbstractInsnNode): BasicValue? {
|
||||
if (insn.opcode == Opcodes.NEW) {
|
||||
uninitializedValuesToCopyUsages.getOrPut(insn) { mutableSetOf() }
|
||||
uninitializedValuesToCopyUsages[insn] = mutableSetOf()
|
||||
return UninitializedNewValue(insn as TypeInsnNode, insn.desc)
|
||||
}
|
||||
return super.newOperation(insn)
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.codegen.AsmUtil;
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilder;
|
||||
import org.jetbrains.kotlin.codegen.FieldInfo;
|
||||
import org.jetbrains.kotlin.codegen.StackValue;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
@@ -68,7 +68,7 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
public void visit(int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) {
|
||||
InlineCodegenUtil.assertVersionNotGreaterThanGeneratedOne(version, name, inliningContext.state);
|
||||
classBuilder.defineClass(null, version, access, name, signature, superName, interfaces);
|
||||
if(CoroutineCodegenUtilKt.COROUTINE_IMPL_ASM_TYPE.getInternalName().equals(superName)) {
|
||||
if(AsmTypes.COROUTINE_IMPL.getInternalName().equals(superName)) {
|
||||
inliningContext.setContinuation(true);
|
||||
}
|
||||
}
|
||||
@@ -141,12 +141,12 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
List<CapturedParamInfo> additionalFakeParams =
|
||||
extractParametersMappingAndPatchConstructor(constructor, allCapturedParamBuilder, constructorParamBuilder,
|
||||
transformationInfo, parentRemapper);
|
||||
List<DeferredMethodVisitor> deferringMethods = new ArrayList<DeferredMethodVisitor>();
|
||||
List<MethodVisitor> deferringMethods = new ArrayList<MethodVisitor>();
|
||||
|
||||
generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, parentRemapper, additionalFakeParams);
|
||||
|
||||
for (MethodNode next : methodsToTransform) {
|
||||
DeferredMethodVisitor deferringVisitor = newMethod(classBuilder, next);
|
||||
MethodVisitor deferringVisitor = newMethod(classBuilder, next);
|
||||
InlineResult funResult =
|
||||
inlineMethodAndUpdateGlobalResult(parentRemapper, deferringVisitor, next, allCapturedParamBuilder, false);
|
||||
|
||||
@@ -161,8 +161,7 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
deferringMethods.add(deferringVisitor);
|
||||
}
|
||||
|
||||
for (DeferredMethodVisitor method : deferringMethods) {
|
||||
InlineCodegenUtil.removeFinallyMarkers(method.getIntermediate());
|
||||
for (MethodVisitor method : deferringMethods) {
|
||||
method.visitEnd();
|
||||
}
|
||||
|
||||
@@ -314,7 +313,6 @@ public class AnonymousObjectTransformer extends ObjectTransformer<AnonymousObjec
|
||||
MethodNode intermediateMethodNode =
|
||||
new MethodNode(AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
inlineMethodAndUpdateGlobalResult(parentRemapper, intermediateMethodNode, constructor, constructorInlineBuilder, true);
|
||||
InlineCodegenUtil.removeFinallyMarkers(intermediateMethodNode);
|
||||
|
||||
AbstractInsnNode first = intermediateMethodNode.instructions.getFirst();
|
||||
final Label oldStartLabel = first instanceof LabelNode ? ((LabelNode) first).getLabel() : null;
|
||||
|
||||
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment;
|
||||
import org.jetbrains.kotlin.codegen.*;
|
||||
import org.jetbrains.kotlin.codegen.context.*;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.SuspendFunctionGenerationStrategy;
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
@@ -239,19 +238,19 @@ public class InlineCodegen extends CallGenerator {
|
||||
assert resolvedCall != null : "Resolved call for " + functionDescriptor + " should be not null";
|
||||
Map<TypeParameterDescriptor, KotlinType> arguments = resolvedCall.getTypeArguments();
|
||||
assert arguments.size() == 1 : "Resolved call for " + functionDescriptor + " should have 1 type argument";
|
||||
|
||||
KotlinType type = arguments.values().iterator().next();
|
||||
MethodNode node =
|
||||
InlineCodegenUtil.createSpecialEnumMethodBody(
|
||||
codegen,
|
||||
functionDescriptor.getName().asString(),
|
||||
arguments.keySet().iterator().next().getDefaultType(),
|
||||
type,
|
||||
codegen.getState().getTypeMapper()
|
||||
);
|
||||
return new SMAPAndMethodNode(node, SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1));
|
||||
}
|
||||
else if (CoroutineCodegenUtilKt.isBuiltInSuspendCoroutineOrReturnInJvm(functionDescriptor)) {
|
||||
else if (CoroutineCodegenUtilKt.isBuiltInSuspendWithCurrentContinuation(functionDescriptor)) {
|
||||
return new SMAPAndMethodNode(
|
||||
CoroutineCodegenUtilKt.createMethodNodeForSuspendCoroutineOrReturn(
|
||||
CoroutineCodegenUtilKt.createMethodNodeForSuspendWithCurrentContinuation(
|
||||
functionDescriptor, codegen.getState().getTypeMapper()
|
||||
),
|
||||
SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1)
|
||||
@@ -466,9 +465,7 @@ public class InlineCodegen extends CallGenerator {
|
||||
adapter, infos, ((StackValue.Local) remapper.remap(parameters.getArgsSizeOnStack() + 1).value).index
|
||||
);
|
||||
removeStaticInitializationTrigger(adapter);
|
||||
if (!InlineCodegenUtil.isFinallyMarkerRequired(codegen.getContext())) {
|
||||
InlineCodegenUtil.removeFinallyMarkers(adapter);
|
||||
}
|
||||
removeFinallyMarkers(adapter);
|
||||
|
||||
adapter.accept(new MethodBodyVisitor(codegen.v));
|
||||
|
||||
@@ -482,9 +479,9 @@ public class InlineCodegen extends CallGenerator {
|
||||
@NotNull
|
||||
private static CallableMemberDescriptor getLabelOwnerDescriptor(@NotNull MethodContext context) {
|
||||
if (context.getParentContext() instanceof ClosureContext &&
|
||||
((ClosureContext) context.getParentContext()).getOriginalSuspendLambdaDescriptor() != null) {
|
||||
((ClosureContext) context.getParentContext()).getCoroutineDescriptor() != null) {
|
||||
//noinspection ConstantConditions
|
||||
return ((ClosureContext) context.getParentContext()).getOriginalSuspendLambdaDescriptor();
|
||||
return ((ClosureContext) context.getParentContext()).getCoroutineDescriptor();
|
||||
}
|
||||
|
||||
return context.getContextDescriptor();
|
||||
@@ -604,14 +601,6 @@ public class InlineCodegen extends CallGenerator {
|
||||
else if (expression instanceof KtFunctionLiteral) {
|
||||
strategy = new ClosureGenerationStrategy(state, (KtDeclarationWithBody) expression);
|
||||
}
|
||||
else if (descriptor.isSuspend() && expression instanceof KtFunction) {
|
||||
strategy =
|
||||
new SuspendFunctionGenerationStrategy(
|
||||
state,
|
||||
CoroutineCodegenUtilKt.<FunctionDescriptor>unwrapInitialDescriptorForSuspendFunction(descriptor),
|
||||
(KtFunction) expression
|
||||
);
|
||||
}
|
||||
else {
|
||||
strategy = new FunctionGenerationStrategy.FunctionDefault(state, (KtDeclarationWithBody) expression);
|
||||
}
|
||||
@@ -1026,6 +1015,25 @@ public class InlineCodegen extends CallGenerator {
|
||||
//processor.substituteLocalVarTable(intoNode);
|
||||
}
|
||||
|
||||
private void removeFinallyMarkers(@NotNull MethodNode intoNode) {
|
||||
if (InlineCodegenUtil.isFinallyMarkerRequired(codegen.getContext())) return;
|
||||
|
||||
InsnList instructions = intoNode.instructions;
|
||||
AbstractInsnNode curInstr = instructions.getFirst();
|
||||
while (curInstr != null) {
|
||||
if (InlineCodegenUtil.isFinallyMarker(curInstr)) {
|
||||
AbstractInsnNode marker = curInstr;
|
||||
//just to assert
|
||||
getConstant(marker.getPrevious());
|
||||
curInstr = curInstr.getNext();
|
||||
instructions.remove(marker.getPrevious());
|
||||
instructions.remove(marker);
|
||||
continue;
|
||||
}
|
||||
curInstr = curInstr.getNext();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap, @NotNull SourceMapper parent) {
|
||||
return new NestedSourceMapper(parent, nodeAndSmap.getSortedRanges(), nodeAndSmap.getClassSMAP().getSourceInfo());
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.backend.common.output.OutputFile;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil;
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.kotlin.codegen.MemberCodegen;
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
||||
@@ -61,9 +60,6 @@ import java.io.StringWriter;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.ENUM_TYPE;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_CLASS_TYPE;
|
||||
|
||||
public class InlineCodegenUtil {
|
||||
public static final boolean GENERATE_SMAP = true;
|
||||
public static final int API = Opcodes.ASM5;
|
||||
@@ -81,9 +77,7 @@ public class InlineCodegenUtil {
|
||||
private static final String INLINE_MARKER_AFTER_METHOD_NAME = "afterInlineCall";
|
||||
private static final String INLINE_MARKER_FINALLY_START = "finallyStart";
|
||||
private static final String INLINE_MARKER_FINALLY_END = "finallyEnd";
|
||||
public static final String SPECIAL_TRANSFORMATION_NAME = "$special";
|
||||
public static final String INLINE_TRANSFORMATION_SUFFIX = "$inlined";
|
||||
public static final String INLINE_CALL_TRANSFORMATION_SUFFIX = "$" + INLINE_TRANSFORMATION_SUFFIX;
|
||||
public static final String INLINE_FUN_THIS_0_SUFFIX = "$inline_fun";
|
||||
public static final String INLINE_FUN_VAR_SUFFIX = "$iv";
|
||||
|
||||
@@ -466,23 +460,6 @@ public class InlineCodegenUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeFinallyMarkers(@NotNull MethodNode intoNode) {
|
||||
InsnList instructions = intoNode.instructions;
|
||||
AbstractInsnNode curInstr = instructions.getFirst();
|
||||
while (curInstr != null) {
|
||||
if (isFinallyMarker(curInstr)) {
|
||||
AbstractInsnNode marker = curInstr;
|
||||
//just to assert
|
||||
getConstant(marker.getPrevious());
|
||||
curInstr = curInstr.getNext();
|
||||
instructions.remove(marker.getPrevious());
|
||||
instructions.remove(marker);
|
||||
continue;
|
||||
}
|
||||
curInstr = curInstr.getNext();
|
||||
}
|
||||
}
|
||||
|
||||
public static void addInlineMarker(@NotNull InstructionAdapter v, boolean isStartNotEnd) {
|
||||
v.visitMethodInsn(
|
||||
Opcodes.INVOKESTATIC, INLINE_MARKER_CLASS_NAME,
|
||||
@@ -553,7 +530,7 @@ public class InlineCodegenUtil {
|
||||
if (!(containingDeclaration instanceof PackageFragmentDescriptor)) {
|
||||
return false;
|
||||
}
|
||||
if (!((PackageFragmentDescriptor) containingDeclaration).getFqName().equals(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME)) {
|
||||
if (!containingDeclaration.getName().equals(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME)) {
|
||||
return false;
|
||||
}
|
||||
if (functionDescriptor.getTypeParameters().size() != 1) {
|
||||
@@ -571,30 +548,23 @@ public class InlineCodegenUtil {
|
||||
@NotNull KotlinType type,
|
||||
@NotNull KotlinTypeMapper typeMapper
|
||||
) {
|
||||
boolean isValueOf = "enumValueOf".equals(name);
|
||||
boolean isEnumValues = "enumValues".equals(name);
|
||||
Type invokeType = typeMapper.mapType(type);
|
||||
String desc = getSpecialEnumFunDescriptor(invokeType, isValueOf);
|
||||
MethodNode node = new MethodNode(API, Opcodes.ACC_STATIC, "fake", desc, null, null);
|
||||
codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.ENUM_REIFIED, new InstructionAdapter(node));
|
||||
if (isValueOf) {
|
||||
node.visitInsn(Opcodes.ACONST_NULL);
|
||||
node.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
String desc = getSpecialEnumFunDescriptor(invokeType, isEnumValues);
|
||||
|
||||
node.visitMethodInsn(Opcodes.INVOKESTATIC, ENUM_TYPE.getInternalName(), "valueOf",
|
||||
Type.getMethodDescriptor(ENUM_TYPE, JAVA_CLASS_TYPE, AsmTypes.JAVA_STRING_TYPE), false);
|
||||
}
|
||||
else {
|
||||
node.visitInsn(Opcodes.ICONST_0);
|
||||
node.visitTypeInsn(Opcodes.ANEWARRAY, ENUM_TYPE.getInternalName());
|
||||
MethodNode node = new MethodNode(API, Opcodes.ACC_STATIC, "fake", desc, null, null);
|
||||
if (!isEnumValues) {
|
||||
node.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
}
|
||||
codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.ENUM_REIFIED, new InstructionAdapter(node));
|
||||
node.visitMethodInsn(Opcodes.INVOKESTATIC, invokeType.getInternalName(), isEnumValues ? "values" : "valueOf", desc, false);
|
||||
node.visitInsn(Opcodes.ARETURN);
|
||||
node.visitMaxs(isValueOf ? 3 : 2, isValueOf ? 1 : 0);
|
||||
node.visitMaxs(isEnumValues ? 2 : 3, isEnumValues ? 0 : 1);
|
||||
return node;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getSpecialEnumFunDescriptor(@NotNull Type type, boolean isValueOf) {
|
||||
return isValueOf ? Type.getMethodDescriptor(type, AsmTypes.JAVA_STRING_TYPE) : Type.getMethodDescriptor(AsmUtil.getArrayType(type));
|
||||
public static String getSpecialEnumFunDescriptor(@NotNull Type type, boolean isEnumValues) {
|
||||
return (isEnumValues ? "()[" : "(Ljava/lang/String;)") + "L" + type.getInternalName() + ";";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -463,7 +463,6 @@ public class MethodInliner {
|
||||
Map<Integer, LambdaInfo> lambdaMapping = new HashMap<Integer, LambdaInfo>();
|
||||
|
||||
int offset = 0;
|
||||
boolean capturesAnonymousObjectThatMustBeRegenerated = false;
|
||||
for (int i = 0; i < paramCount; i++) {
|
||||
SourceValue sourceValue = frame.getStack(firstParameterIndex + i);
|
||||
LambdaInfo lambdaInfo = MethodInlinerUtilKt.getLambdaIfExistsAndMarkInstructions(
|
||||
@@ -472,17 +471,12 @@ public class MethodInliner {
|
||||
if (lambdaInfo != null) {
|
||||
lambdaMapping.put(offset, lambdaInfo);
|
||||
}
|
||||
else if (i < argTypes.length && isAnonymousClassThatMustBeRegenerated(argTypes[i])) {
|
||||
capturesAnonymousObjectThatMustBeRegenerated = true;
|
||||
}
|
||||
|
||||
offset += i == 0 ? 1 : argTypes[i - 1].getSize();
|
||||
}
|
||||
|
||||
transformations.add(
|
||||
buildConstructorInvocation(
|
||||
owner, desc, lambdaMapping, awaitClassReification, capturesAnonymousObjectThatMustBeRegenerated
|
||||
)
|
||||
buildConstructorInvocation(owner, desc, lambdaMapping, awaitClassReification)
|
||||
);
|
||||
awaitClassReification = false;
|
||||
}
|
||||
@@ -544,12 +538,6 @@ public class MethodInliner {
|
||||
return node;
|
||||
}
|
||||
|
||||
private boolean isAnonymousClassThatMustBeRegenerated(@Nullable Type type) {
|
||||
if (type == null || type.getSort() != Type.OBJECT) return false;
|
||||
AnonymousObjectTransformationInfo info = inliningContext.findAnonymousObjectTransformationInfo(type.getInternalName());
|
||||
return info != null && info.shouldRegenerate(true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Frame<SourceValue>[] analyzeMethodNodeBeforeInline(@NotNull MethodNode node) {
|
||||
try {
|
||||
@@ -596,8 +584,7 @@ public class MethodInliner {
|
||||
@NotNull String anonymousType,
|
||||
@NotNull String desc,
|
||||
@NotNull Map<Integer, LambdaInfo> lambdaMapping,
|
||||
boolean needReification,
|
||||
boolean capturesAnonymousObjectThatMustBeRegenerated
|
||||
boolean needReification
|
||||
) {
|
||||
boolean memoizeAnonymousObject = inliningContext.findAnonymousObjectTransformationInfo(anonymousType) == null;
|
||||
|
||||
@@ -607,8 +594,7 @@ public class MethodInliner {
|
||||
isAlreadyRegenerated(anonymousType),
|
||||
desc,
|
||||
false,
|
||||
inliningContext.nameGenerator,
|
||||
capturesAnonymousObjectThatMustBeRegenerated
|
||||
inliningContext.nameGenerator
|
||||
);
|
||||
|
||||
if (memoizeAnonymousObject) {
|
||||
|
||||
@@ -16,13 +16,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.context.MethodContext
|
||||
import org.jetbrains.kotlin.codegen.generateAsCast
|
||||
import org.jetbrains.kotlin.codegen.generateIsCheck
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.intConstant
|
||||
import org.jetbrains.kotlin.codegen.optimization.removeNodeGetNext
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
@@ -141,7 +139,7 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?)
|
||||
OperationKind.SAFE_AS -> processAs(insn, instructions, kotlinType, asmType, safe = true)
|
||||
OperationKind.IS -> processIs(insn, instructions, kotlinType, asmType)
|
||||
OperationKind.JAVA_CLASS -> processJavaClass(insn, asmType)
|
||||
OperationKind.ENUM_REIFIED -> processSpecialEnumFunction(insn, instructions, asmType)
|
||||
OperationKind.ENUM_REIFIED -> processSpecialEnumFunction(insn, asmType)
|
||||
}) {
|
||||
instructions.remove(insn.previous.previous!!) // PUSH operation ID
|
||||
instructions.remove(insn.previous!!) // PUSH type parameter
|
||||
@@ -223,27 +221,12 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun processSpecialEnumFunction(insn: MethodInsnNode, instructions: InsnList, parameter: Type): Boolean {
|
||||
val next1 = insn.next ?: return false
|
||||
val next2 = next1.next ?: return false
|
||||
if (next1.opcode == Opcodes.ACONST_NULL && next2.opcode == Opcodes.ALOAD) {
|
||||
val next3 = next2.next ?: return false
|
||||
if (next3 is MethodInsnNode && next3.name == "valueOf") {
|
||||
instructions.remove(next1)
|
||||
next3.owner = parameter.internalName
|
||||
next3.desc = InlineCodegenUtil.getSpecialEnumFunDescriptor(parameter, true)
|
||||
return true
|
||||
}
|
||||
}
|
||||
else if (next1.opcode == Opcodes.ICONST_0 && next2.opcode == Opcodes.ANEWARRAY) {
|
||||
instructions.remove(next1)
|
||||
instructions.remove(next2)
|
||||
val desc = InlineCodegenUtil.getSpecialEnumFunDescriptor(parameter, false)
|
||||
instructions.insert(insn, MethodInsnNode(Opcodes.INVOKESTATIC, parameter.internalName, "values", desc, false))
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
private fun processSpecialEnumFunction(insn: MethodInsnNode, parameter: Type): Boolean {
|
||||
val next = insn.next
|
||||
if (next !is MethodInsnNode) return false
|
||||
next.owner = parameter.internalName
|
||||
next.desc = InlineCodegenUtil.getSpecialEnumFunDescriptor(parameter, "values" == next.name)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,8 +68,7 @@ class AnonymousObjectTransformationInfo internal constructor(
|
||||
private val alreadyRegenerated: Boolean,
|
||||
val constructorDesc: String?,
|
||||
private val isStaticOrigin: Boolean,
|
||||
parentNameGenerator: NameGenerator,
|
||||
private val capturesAnonymousObjectThatMustBeRegenerated: Boolean = false
|
||||
parentNameGenerator: NameGenerator
|
||||
) : TransformationInfo {
|
||||
|
||||
override val nameGenerator by lazy {
|
||||
@@ -94,8 +93,7 @@ class AnonymousObjectTransformationInfo internal constructor(
|
||||
) : this(ownerInternalName, needReification, hashMapOf(), false, alreadyRegenerated, null, isStaticOrigin, nameGenerator)
|
||||
|
||||
override fun shouldRegenerate(sameModule: Boolean): Boolean =
|
||||
!alreadyRegenerated &&
|
||||
(!lambdasToInline.isEmpty() || !sameModule || capturedOuterRegenerated || needReification || capturesAnonymousObjectThatMustBeRegenerated)
|
||||
!alreadyRegenerated && (!lambdasToInline.isEmpty() || !sameModule || capturedOuterRegenerated || needReification)
|
||||
|
||||
override fun canRemoveAfterTransformation(): Boolean {
|
||||
// Note: It is unsafe to remove anonymous class that is referenced by GETSTATIC within lambda
|
||||
|
||||
@@ -25,7 +25,7 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
class CompareTo : IntrinsicMethod() {
|
||||
private fun genInvoke(type: Type?, v: InstructionAdapter) {
|
||||
when (type) {
|
||||
Type.INT_TYPE, Type.CHAR_TYPE -> v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "compare", "(II)I", false)
|
||||
Type.INT_TYPE -> v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "compare", "(II)I", false)
|
||||
Type.LONG_TYPE -> v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "compare", "(JJ)I", false)
|
||||
Type.FLOAT_TYPE -> v.invokestatic("java/lang/Float", "compare", "(FF)I", false)
|
||||
Type.DOUBLE_TYPE -> v.invokestatic("java/lang/Double", "compare", "(DD)I", false)
|
||||
|
||||
@@ -47,12 +47,12 @@ class Concat : IntrinsicMethod() {
|
||||
codegen.invokeAppend(element.right)
|
||||
}
|
||||
else {
|
||||
// Explicit plus call LHS?.plus(RHS) or LHS.plus(RHS)
|
||||
receiver.put(AsmTypes.JAVA_STRING_TYPE, v)
|
||||
// LHS?.plus(RHS)
|
||||
receiver.put(AsmTypes.OBJECT_TYPE, v)
|
||||
genStringBuilderConstructor(v)
|
||||
v.swap()
|
||||
genInvokeAppendMethod(v, returnType)
|
||||
codegen.invokeAppend(arguments[0])
|
||||
codegen.invokeAppend(arguments.get(0))
|
||||
}
|
||||
|
||||
v.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false)
|
||||
|
||||
@@ -16,22 +16,15 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.removeEmptyCatchBlocks
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
class DeadCodeEliminationMethodTransformer : MethodTransformer() {
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
transformWithResult(internalClassName, methodNode)
|
||||
}
|
||||
|
||||
fun transformWithResult(internalClassName: String, methodNode: MethodNode): Result {
|
||||
val removedNodes = HashSet<AbstractInsnNode>()
|
||||
|
||||
val frames = analyze(internalClassName, methodNode, OptimizationBasicInterpreter())
|
||||
val frames = MethodTransformer.analyze(internalClassName, methodNode, OptimizationBasicInterpreter())
|
||||
val insnList = methodNode.instructions
|
||||
val insnsArray = insnList.toArray()
|
||||
|
||||
@@ -39,19 +32,9 @@ class DeadCodeEliminationMethodTransformer : MethodTransformer() {
|
||||
// by try/catch blocks or local variables table.
|
||||
insnsArray.zip(frames).filter {
|
||||
it.second == null && it.first.isMeaningful
|
||||
}.forEach {
|
||||
insnList.remove(it.first)
|
||||
removedNodes.add(it.first)
|
||||
}
|
||||
}.forEach { insnList.remove(it.first) }
|
||||
|
||||
// Remove empty try-catch blocks to make sure we don't break data flow analysis invariants by dead code elimination.
|
||||
methodNode.removeEmptyCatchBlocks()
|
||||
|
||||
return Result(removedNodes)
|
||||
}
|
||||
|
||||
class Result(val removedNodes: Set<AbstractInsnNode>) {
|
||||
fun isRemoved(node: AbstractInsnNode) = removedNodes.contains(node)
|
||||
fun isAlive(node: AbstractInsnNode) = !isRemoved(node)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.removeEmptyCatchBlocks
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
@@ -35,7 +34,6 @@ class LabelNormalizationMethodTransformer : MethodTransformer() {
|
||||
rewriteNonLabelInstructions()
|
||||
rewriteTryCatchBlocks()
|
||||
rewriteLocalVars()
|
||||
methodNode.removeEmptyCatchBlocks()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,8 +37,7 @@ public class OptimizationMethodVisitor extends TransformationMethodVisitor {
|
||||
new RedundantBoxingMethodTransformer(),
|
||||
new RedundantCoercionToUnitTransformer(),
|
||||
new DeadCodeEliminationMethodTransformer(),
|
||||
new RedundantGotoMethodTransformer(),
|
||||
new RedundantNopsCleanupMethodTransformer()
|
||||
new RedundantGotoMethodTransformer()
|
||||
};
|
||||
|
||||
private final boolean disableOptimization;
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.findNextOrNull
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.LineNumberNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
class RedundantNopsCleanupMethodTransformer : MethodTransformer() {
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
// NOP instruction is required, iff one of the following conditions is true:
|
||||
// (a) it is a sole bytecode instruction in a try-catch block (TCB)
|
||||
// (b) it is a sole bytecode instruction is a source code line
|
||||
|
||||
val requiredNops = HashSet<AbstractInsnNode>()
|
||||
|
||||
recordNopsRequiredForSourceCodeLines(methodNode.instructions.first, requiredNops)
|
||||
recordNopsRequiredForTryCatchBlocks(methodNode, requiredNops)
|
||||
|
||||
var current: AbstractInsnNode? = methodNode.instructions.first
|
||||
while (current != null) {
|
||||
if (current.opcode == Opcodes.NOP && !requiredNops.contains(current)) {
|
||||
val toRemove = current
|
||||
current = current.next
|
||||
methodNode.instructions.remove(toRemove)
|
||||
}
|
||||
else {
|
||||
current = current.next
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun recordNopsRequiredForSourceCodeLines(first: AbstractInsnNode, requiredNops: MutableSet<AbstractInsnNode>) {
|
||||
var current: AbstractInsnNode? = first
|
||||
while (current != null) {
|
||||
if (current is LineNumberNode) {
|
||||
val nextLineNumberNode = current.getNextLineNumberNode()
|
||||
requiredNops.addIfNotNull(getRequiredNopInRange(current, nextLineNumberNode))
|
||||
current = nextLineNumberNode
|
||||
}
|
||||
else {
|
||||
current = current.next
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun recordNopsRequiredForTryCatchBlocks(methodNode: MethodNode, requiredNops: MutableSet<AbstractInsnNode>) {
|
||||
for (tcb in methodNode.tryCatchBlocks) {
|
||||
val nop = tcb.start.findNextOrNull { it.isMeaningful }
|
||||
if (nop?.opcode == Opcodes.NOP) {
|
||||
requiredNops.add(nop)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal fun LineNumberNode.getNextLineNumberNode(): LineNumberNode? {
|
||||
var current: AbstractInsnNode? = this
|
||||
while (current != null) {
|
||||
if (current is LineNumberNode && current.line != this.line) {
|
||||
return current
|
||||
}
|
||||
current = current.next
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
internal fun getRequiredNopInRange(firstInclusive: AbstractInsnNode, lastExclusive: AbstractInsnNode?): AbstractInsnNode? {
|
||||
var lastNop: AbstractInsnNode? = null
|
||||
var current: AbstractInsnNode? = firstInclusive
|
||||
while (current != null && current != lastExclusive) {
|
||||
if (current.isMeaningful && current.opcode != Opcodes.NOP) {
|
||||
return null
|
||||
}
|
||||
else if (current.opcode == Opcodes.NOP) {
|
||||
lastNop = current
|
||||
}
|
||||
current = current.next
|
||||
}
|
||||
|
||||
return lastNop
|
||||
}
|
||||
@@ -20,53 +20,35 @@ import com.intellij.openapi.util.Pair
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.utils.toReadOnlyList
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import java.util.*
|
||||
|
||||
abstract class BoxedBasicValue(type: Type) : StrictBasicValue(type) {
|
||||
abstract val descriptor: BoxedValueDescriptor
|
||||
abstract fun taint(): BoxedBasicValue
|
||||
|
||||
override fun equals(other: Any?) = this === other
|
||||
override fun hashCode() = System.identityHashCode(this)
|
||||
}
|
||||
|
||||
|
||||
class CleanBoxedValue(
|
||||
class BoxedBasicValue(
|
||||
boxedType: Type,
|
||||
boxingInsn: AbstractInsnNode,
|
||||
progressionIterator: ProgressionIteratorBasicValue?
|
||||
) : BoxedBasicValue(boxedType) {
|
||||
override val descriptor = BoxedValueDescriptor(boxedType, boxingInsn, progressionIterator)
|
||||
|
||||
private var tainted: TaintedBoxedValue? = null
|
||||
override fun taint(): BoxedBasicValue = tainted ?: TaintedBoxedValue(this).also { tainted = it }
|
||||
}
|
||||
|
||||
|
||||
class TaintedBoxedValue(val boxedBasicValue: CleanBoxedValue) : BoxedBasicValue(boxedBasicValue.type) {
|
||||
override val descriptor get() = boxedBasicValue.descriptor
|
||||
|
||||
override fun taint(): BoxedBasicValue = this
|
||||
}
|
||||
|
||||
|
||||
class BoxedValueDescriptor(
|
||||
val boxedType: Type,
|
||||
val boxingInsn: AbstractInsnNode,
|
||||
val progressionIterator: ProgressionIteratorBasicValue?
|
||||
) {
|
||||
) : StrictBasicValue(boxedType) {
|
||||
private val associatedInsns = HashSet<AbstractInsnNode>()
|
||||
private val unboxingWithCastInsns = HashSet<Pair<AbstractInsnNode, Type>>()
|
||||
private val associatedVariables = HashSet<Int>()
|
||||
private val mergedWith = HashSet<BoxedValueDescriptor>()
|
||||
private val mergedWith = HashSet<BoxedBasicValue>()
|
||||
|
||||
val primitiveType: Type = unboxType(boxedType)
|
||||
var isSafeToRemove = true; private set
|
||||
val unboxedType: Type = getUnboxedType(boxedType)
|
||||
|
||||
fun getAssociatedInsns() = associatedInsns.toReadOnlyList()
|
||||
override fun equals(other: Any?) =
|
||||
this === other
|
||||
|
||||
fun typeEquals(other: BasicValue) =
|
||||
other is BoxedBasicValue && type == other.type
|
||||
|
||||
override fun hashCode() =
|
||||
System.identityHashCode(this)
|
||||
|
||||
fun getAssociatedInsns(): List<AbstractInsnNode> =
|
||||
ArrayList(associatedInsns)
|
||||
|
||||
fun addInsn(insnNode: AbstractInsnNode) {
|
||||
associatedInsns.add(insnNode)
|
||||
@@ -79,20 +61,22 @@ class BoxedValueDescriptor(
|
||||
fun getVariablesIndexes(): List<Int> =
|
||||
ArrayList(associatedVariables)
|
||||
|
||||
fun addMergedWith(descriptor: BoxedValueDescriptor) {
|
||||
mergedWith.add(descriptor)
|
||||
fun addMergedWith(value: BoxedBasicValue) {
|
||||
mergedWith.add(value)
|
||||
}
|
||||
|
||||
fun getMergedWith(): Iterable<BoxedValueDescriptor> =
|
||||
fun getMergedWith(): Iterable<BoxedBasicValue> =
|
||||
mergedWith
|
||||
|
||||
fun markAsUnsafeToRemove() {
|
||||
isSafeToRemove = false
|
||||
}
|
||||
|
||||
fun isDoubleSize() = unboxedType.size == 2
|
||||
fun isDoubleSize() =
|
||||
primitiveType.size == 2
|
||||
|
||||
fun isFromProgressionIterator() = progressionIterator != null
|
||||
fun isFromProgressionIterator() =
|
||||
progressionIterator != null
|
||||
|
||||
fun addUnboxingWithCastTo(insn: AbstractInsnNode, type: Type) {
|
||||
unboxingWithCastInsns.add(Pair.create(insn, type))
|
||||
@@ -100,14 +84,15 @@ class BoxedValueDescriptor(
|
||||
|
||||
fun getUnboxingWithCastInsns(): Set<Pair<AbstractInsnNode, Type>> =
|
||||
unboxingWithCastInsns
|
||||
}
|
||||
|
||||
|
||||
fun getUnboxedType(boxedType: Type): Type {
|
||||
val primitiveType = AsmUtil.unboxPrimitiveTypeOrNull(boxedType)
|
||||
if (primitiveType != null) return primitiveType
|
||||
|
||||
if (boxedType == AsmTypes.K_CLASS_TYPE) return AsmTypes.JAVA_CLASS_TYPE
|
||||
|
||||
throw IllegalArgumentException("Expected primitive type wrapper or KClass, got: $boxedType")
|
||||
|
||||
companion object {
|
||||
private fun unboxType(boxedType: Type): Type {
|
||||
val primitiveType = AsmUtil.unboxPrimitiveTypeOrNull(boxedType)
|
||||
if (primitiveType != null) return primitiveType
|
||||
|
||||
if (boxedType == AsmTypes.K_CLASS_TYPE) return AsmTypes.JAVA_CLASS_TYPE
|
||||
|
||||
throw IllegalArgumentException("Expected primitive type wrapper or KClass, got: $boxedType")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnList
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import java.util.*
|
||||
|
||||
@@ -38,23 +39,14 @@ open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasic
|
||||
protected open fun createNewBoxing(insn: AbstractInsnNode, type: Type, progressionIterator: ProgressionIteratorBasicValue?): BasicValue {
|
||||
val index = insnList.indexOf(insn)
|
||||
return boxingPlaces.getOrPut(index) {
|
||||
val boxedBasicValue = CleanBoxedValue(type, insn, progressionIterator)
|
||||
val boxedBasicValue = BoxedBasicValue(type, insn, progressionIterator)
|
||||
onNewBoxedValue(boxedBasicValue)
|
||||
boxedBasicValue
|
||||
}
|
||||
}
|
||||
|
||||
protected fun checkUsedValue(value: BasicValue) {
|
||||
if (value is TaintedBoxedValue) {
|
||||
onMergeFail(value)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(AnalyzerException::class)
|
||||
override fun naryOperation(insn: AbstractInsnNode, values: List<BasicValue>): BasicValue? {
|
||||
values.forEach {
|
||||
checkUsedValue(it)
|
||||
}
|
||||
|
||||
val value = super.naryOperation(insn, values)
|
||||
val firstArg = values.firstOrNull() ?: return value
|
||||
|
||||
@@ -88,39 +80,36 @@ open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasic
|
||||
}
|
||||
}
|
||||
|
||||
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue? {
|
||||
checkUsedValue(value)
|
||||
|
||||
return if (insn.opcode == Opcodes.CHECKCAST && isExactValue(value))
|
||||
value
|
||||
else
|
||||
super.unaryOperation(insn, value)
|
||||
}
|
||||
@Throws(AnalyzerException::class)
|
||||
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue? =
|
||||
if (insn.opcode == Opcodes.CHECKCAST && isExactValue(value))
|
||||
value
|
||||
else
|
||||
super.unaryOperation(insn, value)
|
||||
|
||||
protected open fun isExactValue(value: BasicValue) =
|
||||
value is ProgressionIteratorBasicValue ||
|
||||
value is CleanBoxedValue ||
|
||||
value is BoxedBasicValue ||
|
||||
value.type != null && isProgressionClass(value.type.internalName)
|
||||
|
||||
override fun merge(v: BasicValue, w: BasicValue) =
|
||||
when {
|
||||
v == StrictBasicValue.UNINITIALIZED_VALUE || w == StrictBasicValue.UNINITIALIZED_VALUE ->
|
||||
v == StrictBasicValue.UNINITIALIZED_VALUE || w == StrictBasicValue.UNINITIALIZED_VALUE -> {
|
||||
StrictBasicValue.UNINITIALIZED_VALUE
|
||||
v is BoxedBasicValue && w is BoxedBasicValue -> {
|
||||
onMergeSuccess(v, w)
|
||||
when {
|
||||
v is TaintedBoxedValue -> v
|
||||
w is TaintedBoxedValue -> w
|
||||
v.type != w.type -> v.taint()
|
||||
else -> v
|
||||
}
|
||||
}
|
||||
v is BoxedBasicValue ->
|
||||
v.taint()
|
||||
w is BoxedBasicValue ->
|
||||
w.taint()
|
||||
else ->
|
||||
v is BoxedBasicValue && v.typeEquals(w) -> {
|
||||
onMergeSuccess(v, w as BoxedBasicValue)
|
||||
v
|
||||
}
|
||||
else -> {
|
||||
if (v is BoxedBasicValue) {
|
||||
onMergeFail(v)
|
||||
}
|
||||
if (w is BoxedBasicValue) {
|
||||
onMergeFail(w)
|
||||
}
|
||||
super.merge(v, w)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun onNewBoxedValue(value: BoxedBasicValue) {}
|
||||
@@ -208,5 +197,7 @@ private fun isProgressionClass(internalClassName: String) =
|
||||
RangeCodegenUtil.isRangeOrProgression(buildFqNameByInternal(internalClassName))
|
||||
|
||||
private fun getValuesTypeOfProgressionClass(progressionClassInternalName: String) =
|
||||
RangeCodegenUtil.getPrimitiveRangeOrProgressionElementType(buildFqNameByInternal(progressionClassInternalName))
|
||||
?.typeName?.asString() ?: error("type should be not null")
|
||||
RangeCodegenUtil.getPrimitiveRangeOrProgressionElementType(buildFqNameByInternal(progressionClassInternalName))?.let {
|
||||
type ->
|
||||
type.typeName.asString()
|
||||
} ?: error("type should be not null")
|
||||
|
||||
@@ -22,25 +22,25 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
public class RedundantBoxedValuesCollection implements Iterable<BoxedValueDescriptor> {
|
||||
private final Set<BoxedValueDescriptor> safeToDeleteValues = new HashSet<BoxedValueDescriptor>();
|
||||
public class RedundantBoxedValuesCollection implements Iterable<BoxedBasicValue> {
|
||||
private final Set<BoxedBasicValue> safeToDeleteValues = new HashSet<BoxedBasicValue>();
|
||||
|
||||
public void add(@NotNull BoxedValueDescriptor descriptor) {
|
||||
safeToDeleteValues.add(descriptor);
|
||||
public void add(@NotNull BoxedBasicValue value) {
|
||||
safeToDeleteValues.add(value);
|
||||
}
|
||||
|
||||
public void remove(@NotNull BoxedValueDescriptor descriptor) {
|
||||
if (safeToDeleteValues.contains(descriptor)) {
|
||||
safeToDeleteValues.remove(descriptor);
|
||||
descriptor.markAsUnsafeToRemove();
|
||||
public void remove(@NotNull BoxedBasicValue value) {
|
||||
if (safeToDeleteValues.contains(value)) {
|
||||
safeToDeleteValues.remove(value);
|
||||
value.markAsUnsafeToRemove();
|
||||
|
||||
for (BoxedValueDescriptor mergedValueDescriptor : descriptor.getMergedWith()) {
|
||||
remove(mergedValueDescriptor);
|
||||
for (BoxedBasicValue mergedValue : value.getMergedWith()) {
|
||||
remove(mergedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void merge(@NotNull BoxedValueDescriptor v, @NotNull BoxedValueDescriptor w) {
|
||||
public void merge(@NotNull BoxedBasicValue v, @NotNull BoxedBasicValue w) {
|
||||
v.addMergedWith(w);
|
||||
w.addMergedWith(v);
|
||||
|
||||
@@ -59,7 +59,7 @@ public class RedundantBoxedValuesCollection implements Iterable<BoxedValueDescri
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<BoxedValueDescriptor> iterator() {
|
||||
public Iterator<BoxedBasicValue> iterator() {
|
||||
return safeToDeleteValues.iterator();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,12 +23,30 @@ import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnList
|
||||
import org.jetbrains.org.objectweb.asm.tree.TypeInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.VarInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
|
||||
internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterpreter(insnList) {
|
||||
|
||||
val candidatesBoxedValues = RedundantBoxedValuesCollection()
|
||||
|
||||
@Throws(AnalyzerException::class)
|
||||
override fun binaryOperation(insn: AbstractInsnNode, value1: BasicValue, value2: BasicValue): BasicValue? {
|
||||
processOperationWithBoxedValue(value1, insn)
|
||||
processOperationWithBoxedValue(value2, insn)
|
||||
|
||||
return super.binaryOperation(insn, value1, value2)
|
||||
}
|
||||
|
||||
@Throws(AnalyzerException::class)
|
||||
override fun ternaryOperation(insn: AbstractInsnNode, value1: BasicValue, value2: BasicValue, value3: BasicValue): BasicValue? {
|
||||
// in a valid code only aastore could happen with boxed value
|
||||
processOperationWithBoxedValue(value3, insn)
|
||||
|
||||
return super.ternaryOperation(insn, value1, value2, value3)
|
||||
}
|
||||
|
||||
@Throws(AnalyzerException::class)
|
||||
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue? {
|
||||
if ((insn.opcode == Opcodes.CHECKCAST || insn.opcode == Opcodes.INSTANCEOF) && value is BoxedBasicValue) {
|
||||
val typeInsn = insn as TypeInsnNode
|
||||
@@ -43,23 +61,10 @@ internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterprete
|
||||
return super.unaryOperation(insn, value)
|
||||
}
|
||||
|
||||
override fun binaryOperation(insn: AbstractInsnNode, value1: BasicValue, value2: BasicValue): BasicValue? {
|
||||
processOperationWithBoxedValue(value1, insn)
|
||||
processOperationWithBoxedValue(value2, insn)
|
||||
|
||||
return super.binaryOperation(insn, value1, value2)
|
||||
}
|
||||
|
||||
override fun ternaryOperation(insn: AbstractInsnNode, value1: BasicValue, value2: BasicValue, value3: BasicValue): BasicValue? {
|
||||
// in a valid code only aastore could happen with boxed value
|
||||
processOperationWithBoxedValue(value3, insn)
|
||||
|
||||
return super.ternaryOperation(insn, value1, value2, value3)
|
||||
}
|
||||
|
||||
@Throws(AnalyzerException::class)
|
||||
override fun copyOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue {
|
||||
if (value is BoxedBasicValue && insn.opcode == Opcodes.ASTORE) {
|
||||
value.descriptor.addVariableIndex((insn as VarInsnNode).`var`)
|
||||
if (value is BoxedBasicValue && insn.opcode === Opcodes.ASTORE) {
|
||||
value.addVariableIndex((insn as VarInsnNode).`var`)
|
||||
}
|
||||
|
||||
processOperationWithBoxedValue(value, insn)
|
||||
@@ -72,15 +77,15 @@ internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterprete
|
||||
}
|
||||
|
||||
override fun onNewBoxedValue(value: BoxedBasicValue) {
|
||||
candidatesBoxedValues.add(value.descriptor)
|
||||
candidatesBoxedValues.add(value)
|
||||
}
|
||||
|
||||
override fun onUnboxing(insn: AbstractInsnNode, value: BoxedBasicValue, resultType: Type) {
|
||||
value.descriptor.run {
|
||||
if (unboxedType == resultType)
|
||||
addAssociatedInsn(value, insn)
|
||||
else
|
||||
addUnboxingWithCastTo(insn, resultType)
|
||||
if (value.primitiveType == resultType) {
|
||||
addAssociatedInsn(value, insn)
|
||||
}
|
||||
else {
|
||||
value.addUnboxingWithCastTo(insn, resultType)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,13 +98,11 @@ internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterprete
|
||||
}
|
||||
|
||||
override fun onMergeSuccess(v: BoxedBasicValue, w: BoxedBasicValue) {
|
||||
candidatesBoxedValues.merge(v.descriptor, w.descriptor)
|
||||
candidatesBoxedValues.merge(v, w)
|
||||
}
|
||||
|
||||
private fun processOperationWithBoxedValue(value: BasicValue?, insnNode: AbstractInsnNode) {
|
||||
if (value is BoxedBasicValue) {
|
||||
checkUsedValue(value)
|
||||
|
||||
if (!PERMITTED_OPERATIONS_OPCODES.contains(insnNode.opcode)) {
|
||||
markValueAsDirty(value)
|
||||
}
|
||||
@@ -110,7 +113,7 @@ internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterprete
|
||||
}
|
||||
|
||||
private fun markValueAsDirty(value: BoxedBasicValue) {
|
||||
candidatesBoxedValues.remove(value.descriptor)
|
||||
candidatesBoxedValues.remove(value)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -124,15 +127,17 @@ internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterprete
|
||||
when (targetInternalName) {
|
||||
Type.getInternalName(Any::class.java) ->
|
||||
true
|
||||
Type.getInternalName(Number::class.java) ->
|
||||
PRIMITIVE_TYPES_SORTS_WITH_WRAPPER_EXTENDS_NUMBER.contains(value.descriptor.unboxedType.sort)
|
||||
Type.getInternalName(Number::class.java) -> {
|
||||
PRIMITIVE_TYPES_SORTS_WITH_WRAPPER_EXTENDS_NUMBER.contains(
|
||||
value.primitiveType.sort)
|
||||
}
|
||||
else ->
|
||||
value.type.internalName == targetInternalName
|
||||
value.type.internalName.equals(targetInternalName)
|
||||
}
|
||||
|
||||
private fun addAssociatedInsn(value: BoxedBasicValue, insn: AbstractInsnNode) {
|
||||
value.descriptor.run {
|
||||
if (isSafeToRemove) addInsn(insn)
|
||||
if (value.isSafeToRemove) {
|
||||
value.addInsn(insn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.boxing;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
@@ -36,8 +38,9 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
@Override
|
||||
public void transform(@NotNull String internalClassName, @NotNull MethodNode node) {
|
||||
RedundantBoxingInterpreter interpreter = new RedundantBoxingInterpreter(node.instructions);
|
||||
Frame<BasicValue>[] frames = analyze(internalClassName, node, interpreter);
|
||||
|
||||
Frame<BasicValue>[] frames = analyze(
|
||||
internalClassName, node, interpreter
|
||||
);
|
||||
interpretPopInstructionsForBoxedValues(interpreter, node, frames);
|
||||
|
||||
RedundantBoxedValuesCollection valuesToOptimize = interpreter.getCandidatesBoxedValues();
|
||||
@@ -96,25 +99,32 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<BasicValue> variableValues = getValuesStoredOrLoadedToVariable(localVariableNode, node, frames);
|
||||
List<BasicValue> usedValues = getValuesStoredOrLoadedToVariable(localVariableNode, node, frames);
|
||||
|
||||
Collection<BasicValue> boxed = CollectionsKt.filter(variableValues, new Function1<BasicValue, Boolean>() {
|
||||
Collection<BasicValue> boxed = Collections2.filter(usedValues, new Predicate<BasicValue>() {
|
||||
@Override
|
||||
public Boolean invoke(BasicValue value) {
|
||||
return value instanceof BoxedBasicValue;
|
||||
public boolean apply(BasicValue input) {
|
||||
return input instanceof BoxedBasicValue;
|
||||
}
|
||||
});
|
||||
|
||||
if (boxed.isEmpty()) continue;
|
||||
|
||||
BoxedValueDescriptor firstBoxed = ((BoxedBasicValue) boxed.iterator().next()).getDescriptor();
|
||||
if (isUnsafeToRemoveBoxingForConnectedValues(variableValues, firstBoxed.getUnboxedType())) {
|
||||
for (BasicValue value : variableValues) {
|
||||
if (!(value instanceof BoxedBasicValue)) continue;
|
||||
final BoxedBasicValue firstBoxed = (BoxedBasicValue) boxed.iterator().next();
|
||||
|
||||
BoxedValueDescriptor descriptor = ((BoxedBasicValue) value).getDescriptor();
|
||||
if (descriptor.isSafeToRemove()) {
|
||||
values.remove(descriptor);
|
||||
if (CollectionsKt.any(usedValues, new Function1<BasicValue, Boolean>() {
|
||||
@Override
|
||||
public Boolean invoke(BasicValue input) {
|
||||
if (input == StrictBasicValue.UNINITIALIZED_VALUE) return false;
|
||||
return input == null ||
|
||||
!(input instanceof BoxedBasicValue) ||
|
||||
!((BoxedBasicValue) input).isSafeToRemove() ||
|
||||
!((BoxedBasicValue) input).getPrimitiveType().equals(firstBoxed.getPrimitiveType());
|
||||
}
|
||||
})) {
|
||||
for (BasicValue value : usedValues) {
|
||||
if (value instanceof BoxedBasicValue && ((BoxedBasicValue) value).isSafeToRemove()) {
|
||||
values.remove((BoxedBasicValue) value);
|
||||
needToRepeat = true;
|
||||
}
|
||||
}
|
||||
@@ -124,20 +134,6 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
return needToRepeat;
|
||||
}
|
||||
|
||||
private static boolean isUnsafeToRemoveBoxingForConnectedValues(List<BasicValue> usedValues, final Type unboxedType) {
|
||||
return CollectionsKt.any(usedValues, new Function1<BasicValue, Boolean>() {
|
||||
@Override
|
||||
public Boolean invoke(BasicValue input) {
|
||||
if (input == StrictBasicValue.UNINITIALIZED_VALUE) return false;
|
||||
if (!(input instanceof BoxedBasicValue)) return true;
|
||||
|
||||
BoxedValueDescriptor descriptor = ((BoxedBasicValue) input).getDescriptor();
|
||||
return !descriptor.isSafeToRemove() ||
|
||||
!(descriptor.getUnboxedType().equals(unboxedType));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void adaptLocalVariableTableForBoxedValues(@NotNull MethodNode node, @NotNull Frame<BasicValue>[] frames) {
|
||||
for (LocalVariableNode localVariableNode : node.localVariables) {
|
||||
if (Type.getType(localVariableNode.desc).getSort() != Type.OBJECT) {
|
||||
@@ -145,11 +141,8 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
}
|
||||
|
||||
for (BasicValue value : getValuesStoredOrLoadedToVariable(localVariableNode, node, frames)) {
|
||||
if (!(value instanceof BoxedBasicValue)) continue;
|
||||
|
||||
BoxedValueDescriptor descriptor = ((BoxedBasicValue) value).getDescriptor();
|
||||
if (!descriptor.isSafeToRemove()) continue;
|
||||
localVariableNode.desc = descriptor.getUnboxedType().getDescriptor();
|
||||
if (value == null || !(value instanceof BoxedBasicValue) || !((BoxedBasicValue) value).isSafeToRemove()) continue;
|
||||
localVariableNode.desc = ((BoxedBasicValue) value).getPrimitiveType().getDescriptor();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,9 +193,9 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
@NotNull
|
||||
private static int[] buildVariablesRemapping(@NotNull RedundantBoxedValuesCollection values, @NotNull MethodNode node) {
|
||||
Set<Integer> doubleSizedVars = new HashSet<Integer>();
|
||||
for (BoxedValueDescriptor valueDescriptor : values) {
|
||||
if (valueDescriptor.isDoubleSize()) {
|
||||
doubleSizedVars.addAll(valueDescriptor.getVariablesIndexes());
|
||||
for (BoxedBasicValue value : values) {
|
||||
if (value.getPrimitiveType().getSize() == 2) {
|
||||
doubleSizedVars.addAll(value.getVariablesIndexes());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,12 +233,12 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
@NotNull MethodNode node,
|
||||
@NotNull RedundantBoxedValuesCollection values
|
||||
) {
|
||||
for (BoxedValueDescriptor value : values) {
|
||||
for (BoxedBasicValue value : values) {
|
||||
adaptInstructionsForBoxedValue(node, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void adaptInstructionsForBoxedValue(@NotNull MethodNode node, @NotNull BoxedValueDescriptor value) {
|
||||
private static void adaptInstructionsForBoxedValue(@NotNull MethodNode node, @NotNull BoxedBasicValue value) {
|
||||
adaptBoxingInstruction(node, value);
|
||||
|
||||
for (Pair<AbstractInsnNode, Type> cast : value.getUnboxingWithCastInsns()) {
|
||||
@@ -257,7 +250,7 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
private static void adaptBoxingInstruction(@NotNull MethodNode node, @NotNull BoxedValueDescriptor value) {
|
||||
private static void adaptBoxingInstruction(@NotNull MethodNode node, @NotNull BoxedBasicValue value) {
|
||||
if (!value.isFromProgressionIterator()) {
|
||||
node.instructions.remove(value.getBoxingInsn());
|
||||
}
|
||||
@@ -287,12 +280,12 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
|
||||
private static void adaptCastInstruction(
|
||||
@NotNull MethodNode node,
|
||||
@NotNull BoxedValueDescriptor value,
|
||||
@NotNull BoxedBasicValue value,
|
||||
@NotNull Pair<AbstractInsnNode, Type> castWithType
|
||||
) {
|
||||
AbstractInsnNode castInsn = castWithType.getFirst();
|
||||
MethodNode castInsnsListener = new MethodNode(Opcodes.ASM5);
|
||||
new InstructionAdapter(castInsnsListener).cast(value.getUnboxedType(), castWithType.getSecond());
|
||||
new InstructionAdapter(castInsnsListener).cast(value.getPrimitiveType(), castWithType.getSecond());
|
||||
|
||||
for (AbstractInsnNode insn : castInsnsListener.instructions.toArray()) {
|
||||
node.instructions.insertBefore(castInsn, insn);
|
||||
@@ -302,7 +295,7 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
}
|
||||
|
||||
private static void adaptInstruction(
|
||||
@NotNull MethodNode node, @NotNull AbstractInsnNode insn, @NotNull BoxedValueDescriptor value
|
||||
@NotNull MethodNode node, @NotNull AbstractInsnNode insn, @NotNull BoxedBasicValue value
|
||||
) {
|
||||
boolean isDoubleSize = value.isDoubleSize();
|
||||
|
||||
@@ -329,7 +322,7 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
|
||||
node.instructions.set(
|
||||
insn,
|
||||
new VarInsnNode(
|
||||
value.getUnboxedType().getOpcode(intVarOpcode),
|
||||
value.getPrimitiveType().getOpcode(intVarOpcode),
|
||||
((VarInsnNode) insn).var
|
||||
)
|
||||
);
|
||||
|
||||
@@ -32,8 +32,15 @@ import java.util.List;
|
||||
import static org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue.*;
|
||||
|
||||
public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implements Opcodes {
|
||||
public OptimizationBasicInterpreter() {
|
||||
private final boolean tolerantToUninitializedValues;
|
||||
|
||||
public OptimizationBasicInterpreter(boolean tolerantToUninitializedValues) {
|
||||
super(ASM5);
|
||||
this.tolerantToUninitializedValues = tolerantToUninitializedValues;
|
||||
}
|
||||
|
||||
public OptimizationBasicInterpreter() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,9 +79,13 @@ public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implem
|
||||
|
||||
@Override
|
||||
public BasicValue newOperation(@NotNull AbstractInsnNode insn) throws AnalyzerException {
|
||||
if (insn.getOpcode() == Opcodes.ACONST_NULL) {
|
||||
return newValue(Type.getObjectType("java/lang/Object"));
|
||||
}
|
||||
|
||||
switch (insn.getOpcode()) {
|
||||
case ACONST_NULL:
|
||||
return NULL_VALUE;
|
||||
return newValue(Type.getObjectType("null"));
|
||||
case ICONST_M1:
|
||||
case ICONST_0:
|
||||
case ICONST_1:
|
||||
@@ -351,16 +362,17 @@ public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implem
|
||||
) {
|
||||
if (v.equals(w)) return v;
|
||||
|
||||
if (v == StrictBasicValue.UNINITIALIZED_VALUE || w == StrictBasicValue.UNINITIALIZED_VALUE) {
|
||||
if (tolerantToUninitializedValues) {
|
||||
if (v == StrictBasicValue.UNINITIALIZED_VALUE) return w;
|
||||
if (w == StrictBasicValue.UNINITIALIZED_VALUE) return v;
|
||||
}
|
||||
else if (v == StrictBasicValue.UNINITIALIZED_VALUE || w == StrictBasicValue.UNINITIALIZED_VALUE) {
|
||||
return StrictBasicValue.UNINITIALIZED_VALUE;
|
||||
}
|
||||
|
||||
// if merge of two references then `lub` is java/lang/Object
|
||||
// arrays also are BasicValues with reference type's
|
||||
if (isReference(v) && isReference(w)) {
|
||||
if (v == NULL_VALUE) return newValue(w.getType());
|
||||
if (w == NULL_VALUE) return newValue(v.getType());
|
||||
|
||||
return StrictBasicValue.REFERENCE_VALUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,9 +45,6 @@ open class StrictBasicValue(type: Type?) : BasicValue(type) {
|
||||
val SHORT_VALUE = StrictBasicValue(Type.SHORT_TYPE)
|
||||
@JvmField
|
||||
val REFERENCE_VALUE = StrictBasicValue(Type.getObjectType("java/lang/Object"))
|
||||
|
||||
@JvmField
|
||||
val NULL_VALUE = StrictBasicValue(Type.getObjectType("java/lang/Object"))
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
@@ -63,9 +60,4 @@ open class StrictBasicValue(type: Type?) : BasicValue(type) {
|
||||
}
|
||||
|
||||
override fun hashCode() = (type?.hashCode() ?: 0)
|
||||
|
||||
override fun toString(): String {
|
||||
if (this === UNINITIALIZED_VALUE) return "."
|
||||
return super.toString()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.common
|
||||
|
||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
@@ -121,7 +120,3 @@ fun insnListOf(vararg insns: AbstractInsnNode) = InsnList().apply { insns.forEac
|
||||
|
||||
fun AbstractInsnNode.isStoreOperation(): Boolean = getOpcode() in Opcodes.ISTORE..Opcodes.ASTORE
|
||||
fun AbstractInsnNode.isLoadOperation(): Boolean = getOpcode() in Opcodes.ILOAD..Opcodes.ALOAD
|
||||
|
||||
val AbstractInsnNode?.insnText get() = InlineCodegenUtil.getInsnText(this)
|
||||
val AbstractInsnNode?.debugText get() =
|
||||
if (this == null) "<null>" else "${this.javaClass.simpleName}: $insnText"
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.fixStack
|
||||
|
||||
import com.sun.xml.internal.ws.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.findNextOrNull
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.hasOpcode
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.LabelNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
@@ -22,187 +22,138 @@ import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
|
||||
|
||||
internal class FixStackAnalyzer(
|
||||
owner: String,
|
||||
val method: MethodNode,
|
||||
methodNode: MethodNode,
|
||||
val context: FixStackContext
|
||||
) {
|
||||
companion object {
|
||||
// Stack size is always non-negative
|
||||
const val DEAD_CODE_STACK_SIZE = -1
|
||||
) : MethodAnalyzer<BasicValue>(owner, methodNode, OptimizationBasicInterpreter(/* tolerantToUninitializedValues = */true)) {
|
||||
val savedStacks = hashMapOf<AbstractInsnNode, List<BasicValue>>()
|
||||
var maxExtraStackSize = 0; private set
|
||||
|
||||
override fun visitControlFlowEdge(insn: Int, successor: Int): Boolean {
|
||||
val insnNode = instructions[insn]
|
||||
return !(insnNode is JumpInsnNode && context.breakContinueGotoNodes.contains(insnNode))
|
||||
}
|
||||
|
||||
private val expectedStackNode = hashMapOf<LabelNode, AbstractInsnNode>()
|
||||
override fun newFrame(nLocals: Int, nStack: Int): Frame<BasicValue> =
|
||||
FixStackFrame(nLocals, nStack)
|
||||
|
||||
val maxExtraStackSize: Int get() = analyzer.maxExtraStackSize
|
||||
private fun indexOf(node: AbstractInsnNode) = method.instructions.indexOf(node)
|
||||
|
||||
fun getStackToSpill(location: AbstractInsnNode) = analyzer.spilledStacks[location]
|
||||
fun getActualStack(location: AbstractInsnNode) = getFrame(location)?.getStackContent()
|
||||
fun getActualStackSize(location: AbstractInsnNode) = getFrame(location)?.stackSizeWithExtra ?: DEAD_CODE_STACK_SIZE
|
||||
fun getExpectedStackSize(location: AbstractInsnNode) = getExpectedStackFrame(location)?.stackSizeWithExtra ?: DEAD_CODE_STACK_SIZE
|
||||
inner class FixStackFrame(nLocals: Int, nStack: Int) : Frame<BasicValue>(nLocals, nStack) {
|
||||
val extraStack = Stack<BasicValue>()
|
||||
|
||||
private fun getExpectedStackFrame(location: AbstractInsnNode) = getFrame(expectedStackNode[location] ?: location)
|
||||
private fun getFrame(location: AbstractInsnNode) = analyzer.getFrame(location) as? InternalAnalyzer.FixStackFrame
|
||||
|
||||
fun analyze() {
|
||||
preprocess()
|
||||
analyzer.analyze()
|
||||
}
|
||||
|
||||
private fun preprocess() {
|
||||
for (marker in context.fakeAlwaysFalseIfeqMarkers) {
|
||||
val next = marker.next
|
||||
if (next is JumpInsnNode) {
|
||||
val nop = InsnNode(Opcodes.NOP)
|
||||
expectedStackNode[next.label] = nop
|
||||
method.instructions.insert(next, nop)
|
||||
method.instructions.remove(marker)
|
||||
method.instructions.remove(next)
|
||||
context.nodesToRemoveOnCleanup.add(nop)
|
||||
}
|
||||
override fun init(src: Frame<out BasicValue>): Frame<BasicValue> {
|
||||
extraStack.clear()
|
||||
extraStack.addAll((src as FixStackFrame).extraStack)
|
||||
return super.init(src)
|
||||
}
|
||||
|
||||
context.fakeAlwaysFalseIfeqMarkers.clear()
|
||||
}
|
||||
|
||||
private val analyzer = InternalAnalyzer(owner, method, context)
|
||||
|
||||
private class InternalAnalyzer(
|
||||
owner: String,
|
||||
method: MethodNode,
|
||||
val context: FixStackContext
|
||||
) : MethodAnalyzer<BasicValue>(owner, method, OptimizationBasicInterpreter()) {
|
||||
val spilledStacks = hashMapOf<AbstractInsnNode, List<BasicValue>>()
|
||||
var maxExtraStackSize = 0; private set
|
||||
|
||||
override fun visitControlFlowEdge(insn: Int, successor: Int): Boolean {
|
||||
val insnNode = instructions[insn]
|
||||
return !(insnNode is JumpInsnNode && context.breakContinueGotoNodes.contains(insnNode))
|
||||
override fun clearStack() {
|
||||
extraStack.clear()
|
||||
super.clearStack()
|
||||
}
|
||||
|
||||
override fun newFrame(nLocals: Int, nStack: Int): Frame<BasicValue> =
|
||||
FixStackFrame(nLocals, nStack)
|
||||
|
||||
private fun indexOf(node: AbstractInsnNode) = method.instructions.indexOf(node)
|
||||
|
||||
inner class FixStackFrame(nLocals: Int, nStack: Int) : Frame<BasicValue>(nLocals, nStack) {
|
||||
val extraStack = Stack<BasicValue>()
|
||||
|
||||
override fun init(src: Frame<out BasicValue>): Frame<BasicValue> {
|
||||
extraStack.clear()
|
||||
extraStack.addAll((src as FixStackFrame).extraStack)
|
||||
return super.init(src)
|
||||
}
|
||||
|
||||
override fun clearStack() {
|
||||
extraStack.clear()
|
||||
super.clearStack()
|
||||
}
|
||||
|
||||
override fun execute(insn: AbstractInsnNode, interpreter: Interpreter<BasicValue>) {
|
||||
when {
|
||||
PseudoInsn.SAVE_STACK_BEFORE_TRY.isa(insn) ->
|
||||
executeSaveStackBeforeTry(insn)
|
||||
PseudoInsn.RESTORE_STACK_IN_TRY_CATCH.isa(insn) ->
|
||||
executeRestoreStackInTryCatch(insn)
|
||||
InlineCodegenUtil.isBeforeInlineMarker(insn) ->
|
||||
executeBeforeInlineCallMarker(insn)
|
||||
InlineCodegenUtil.isAfterInlineMarker(insn) ->
|
||||
executeAfterInlineCallMarker(insn)
|
||||
InlineCodegenUtil.isMarkedReturn(insn) -> {
|
||||
// KT-9644: might throw "Incompatible return type" on non-local return, in fact we don't care.
|
||||
if (insn.opcode == Opcodes.RETURN) return
|
||||
}
|
||||
}
|
||||
|
||||
super.execute(insn, interpreter)
|
||||
}
|
||||
|
||||
val stackSizeWithExtra: Int get() = super.getStackSize() + extraStack.size
|
||||
|
||||
fun getStackContent(): List<BasicValue> {
|
||||
val savedStack = arrayListOf<BasicValue>()
|
||||
IntRange(0, super.getStackSize() - 1).mapTo(savedStack) { super.getStack(it) }
|
||||
savedStack.addAll(extraStack)
|
||||
return savedStack
|
||||
}
|
||||
|
||||
override fun push(value: BasicValue) {
|
||||
if (super.getStackSize() < maxStackSize) {
|
||||
super.push(value)
|
||||
}
|
||||
else {
|
||||
extraStack.add(value)
|
||||
maxExtraStackSize = Math.max(maxExtraStackSize, extraStack.size)
|
||||
override fun execute(insn: AbstractInsnNode, interpreter: Interpreter<BasicValue>) {
|
||||
when {
|
||||
PseudoInsn.SAVE_STACK_BEFORE_TRY.isa(insn) ->
|
||||
executeSaveStackBeforeTry(insn)
|
||||
PseudoInsn.RESTORE_STACK_IN_TRY_CATCH.isa(insn) ->
|
||||
executeRestoreStackInTryCatch(insn)
|
||||
InlineCodegenUtil.isBeforeInlineMarker(insn) ->
|
||||
executeBeforeInlineCallMarker(insn)
|
||||
InlineCodegenUtil.isAfterInlineMarker(insn) ->
|
||||
executeAfterInlineCallMarker(insn)
|
||||
InlineCodegenUtil.isMarkedReturn(insn) -> {
|
||||
// KT-9644: might throw "Incompatible return type" on non-local return, in fact we don't care.
|
||||
if (insn.opcode == Opcodes.RETURN) return
|
||||
}
|
||||
}
|
||||
|
||||
fun pushAll(values: Collection<BasicValue>) {
|
||||
values.forEach { push(it) }
|
||||
}
|
||||
|
||||
override fun pop(): BasicValue {
|
||||
if (extraStack.isNotEmpty()) {
|
||||
return extraStack.pop()
|
||||
}
|
||||
else {
|
||||
return super.pop()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getStack(i: Int): BasicValue {
|
||||
if (i < super.getMaxStackSize()) {
|
||||
return super.getStack(i)
|
||||
}
|
||||
else {
|
||||
return extraStack[i - maxStackSize]
|
||||
}
|
||||
}
|
||||
super.execute(insn, interpreter)
|
||||
}
|
||||
|
||||
private fun FixStackFrame.executeBeforeInlineCallMarker(insn: AbstractInsnNode) {
|
||||
saveStackAndClear(insn)
|
||||
fun getStackContent(): List<BasicValue> {
|
||||
val savedStack = arrayListOf<BasicValue>()
|
||||
IntRange(0, super.getStackSize() - 1).mapTo(savedStack) { super.getStack(it) }
|
||||
savedStack.addAll(extraStack)
|
||||
return savedStack
|
||||
}
|
||||
|
||||
private fun FixStackFrame.saveStackAndClear(insn: AbstractInsnNode) {
|
||||
val savedValues = getStackContent()
|
||||
spilledStacks[insn] = savedValues
|
||||
clearStack()
|
||||
}
|
||||
|
||||
private fun FixStackFrame.executeAfterInlineCallMarker(insn: AbstractInsnNode) {
|
||||
val beforeInlineMarker = context.openingInlineMethodMarker[insn]
|
||||
if (stackSize > 0) {
|
||||
val returnValue = pop()
|
||||
clearStack()
|
||||
val savedValues = spilledStacks[beforeInlineMarker]
|
||||
pushAll(savedValues!!)
|
||||
push(returnValue)
|
||||
override fun push(value: BasicValue) {
|
||||
if (super.getStackSize() < maxStackSize) {
|
||||
super.push(value)
|
||||
}
|
||||
else {
|
||||
val savedValues = spilledStacks[beforeInlineMarker]
|
||||
pushAll(savedValues!!)
|
||||
extraStack.add(value)
|
||||
maxExtraStackSize = Math.max(maxExtraStackSize, extraStack.size)
|
||||
}
|
||||
}
|
||||
|
||||
private fun FixStackFrame.executeRestoreStackInTryCatch(insn: AbstractInsnNode) {
|
||||
val saveNode = context.saveStackMarkerForRestoreMarker[insn]
|
||||
val savedValues = spilledStacks.getOrElse(saveNode!!) {
|
||||
throw AssertionError("${indexOf(insn)}: Restore stack is unavailable for ${indexOf(saveNode)}")
|
||||
}
|
||||
pushAll(savedValues)
|
||||
fun pushAll(values: Collection<BasicValue>) {
|
||||
values.forEach { push(it) }
|
||||
}
|
||||
|
||||
private fun FixStackFrame.executeSaveStackBeforeTry(insn: AbstractInsnNode) {
|
||||
saveStackAndClear(insn)
|
||||
override fun pop(): BasicValue {
|
||||
if (extraStack.isNotEmpty()) {
|
||||
return extraStack.pop()
|
||||
}
|
||||
else {
|
||||
return super.pop()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getStack(i: Int): BasicValue {
|
||||
if (i < super.getMaxStackSize()) {
|
||||
return super.getStack(i)
|
||||
}
|
||||
else {
|
||||
return extraStack[i - maxStackSize]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun FixStackFrame.executeBeforeInlineCallMarker(insn: AbstractInsnNode) {
|
||||
saveStackAndClear(insn)
|
||||
}
|
||||
|
||||
private fun FixStackFrame.saveStackAndClear(insn: AbstractInsnNode) {
|
||||
val savedValues = getStackContent()
|
||||
savedStacks[insn] = savedValues
|
||||
clearStack()
|
||||
}
|
||||
|
||||
private fun FixStackFrame.executeAfterInlineCallMarker(insn: AbstractInsnNode) {
|
||||
val beforeInlineMarker = context.openingInlineMethodMarker[insn]
|
||||
if (stackSize > 0) {
|
||||
val returnValue = pop()
|
||||
clearStack()
|
||||
val savedValues = savedStacks[beforeInlineMarker]
|
||||
pushAll(savedValues!!)
|
||||
push(returnValue)
|
||||
}
|
||||
else {
|
||||
val savedValues = savedStacks[beforeInlineMarker]
|
||||
pushAll(savedValues!!)
|
||||
}
|
||||
}
|
||||
|
||||
private fun FixStackFrame.executeRestoreStackInTryCatch(insn: AbstractInsnNode) {
|
||||
val saveNode = context.saveStackMarkerForRestoreMarker[insn]
|
||||
val savedValues = savedStacks.getOrElse(saveNode!!) {
|
||||
throw AssertionError("${indexOf(insn)}: Restore stack is unavailable for ${indexOf(saveNode)}")
|
||||
}
|
||||
pushAll(savedValues)
|
||||
}
|
||||
|
||||
private fun FixStackFrame.executeSaveStackBeforeTry(insn: AbstractInsnNode) {
|
||||
saveStackAndClear(insn)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,8 +39,6 @@ internal class FixStackContext(val methodNode: MethodNode) {
|
||||
val openingInlineMethodMarker = hashMapOf<AbstractInsnNode, AbstractInsnNode>()
|
||||
var consistentInlineMarkers: Boolean = true; private set
|
||||
|
||||
val nodesToRemoveOnCleanup = arrayListOf<AbstractInsnNode>()
|
||||
|
||||
init {
|
||||
saveStackMarkerForRestoreMarker = insertTryCatchBlocksMarkers(methodNode)
|
||||
isThereAnyTryCatch = saveStackMarkerForRestoreMarker.isNotEmpty()
|
||||
|
||||
@@ -60,10 +60,6 @@ class FixStackMethodTransformer : MethodTransformer() {
|
||||
context.fakeAlwaysFalseIfeqMarkers.forEach { marker ->
|
||||
removeAlwaysFalseIfeq(methodNode, marker)
|
||||
}
|
||||
|
||||
context.nodesToRemoveOnCleanup.forEach {
|
||||
methodNode.instructions.remove(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformBreakContinueGotos(
|
||||
@@ -76,18 +72,16 @@ class FixStackMethodTransformer : MethodTransformer() {
|
||||
val gotoIndex = methodNode.instructions.indexOf(gotoNode)
|
||||
val labelIndex = methodNode.instructions.indexOf(gotoNode.label)
|
||||
|
||||
val actualStackSize = analyzer.getActualStackSize(gotoNode)
|
||||
val expectedStackSize = analyzer.getExpectedStackSize(gotoNode.label)
|
||||
val DEAD_CODE = -1 // Stack size is always non-negative
|
||||
val actualStackSize = analyzer.frames[gotoIndex]?.stackSize ?: DEAD_CODE
|
||||
val expectedStackSize = analyzer.frames[labelIndex]?.stackSize ?: DEAD_CODE
|
||||
|
||||
if (actualStackSize >= 0 && expectedStackSize >= 0) {
|
||||
assert(expectedStackSize <= actualStackSize) {
|
||||
"Label at $labelIndex, jump at $gotoIndex: stack underflow: $expectedStackSize > $actualStackSize"
|
||||
}
|
||||
val actualStackContent = analyzer.getActualStack(gotoNode)
|
||||
?: throw AssertionError("Jump at $gotoIndex should be alive")
|
||||
actions.add({ replaceMarkerWithPops(methodNode, gotoNode.previous, expectedStackSize, actualStackContent) })
|
||||
if (actualStackSize != DEAD_CODE && expectedStackSize != DEAD_CODE) {
|
||||
assert(expectedStackSize <= actualStackSize) { "Label at $labelIndex, jump at $gotoIndex: stack underflow: $expectedStackSize > $actualStackSize" }
|
||||
val frame = analyzer.frames[gotoIndex]!!
|
||||
actions.add({ replaceMarkerWithPops(methodNode, gotoNode.previous, expectedStackSize, frame) })
|
||||
}
|
||||
else if (actualStackSize >= 0 && expectedStackSize < 0) {
|
||||
else if (actualStackSize != DEAD_CODE && expectedStackSize == DEAD_CODE) {
|
||||
throw AssertionError("Live jump $gotoIndex to dead label $labelIndex")
|
||||
}
|
||||
else {
|
||||
@@ -126,7 +120,7 @@ class FixStackMethodTransformer : MethodTransformer() {
|
||||
marker: AbstractInsnNode,
|
||||
localVariablesManager: LocalVariablesManager
|
||||
) {
|
||||
val savedStackValues = analyzer.getStackToSpill(marker)
|
||||
val savedStackValues = analyzer.savedStacks[marker]
|
||||
if (savedStackValues != null) {
|
||||
val savedStackDescriptor = localVariablesManager.allocateVariablesForSaveStackMarker(marker, savedStackValues)
|
||||
actions.add({ saveStack(methodNode, marker, savedStackDescriptor, false) })
|
||||
@@ -157,21 +151,20 @@ class FixStackMethodTransformer : MethodTransformer() {
|
||||
localVariablesManager: LocalVariablesManager
|
||||
) {
|
||||
val savedStackDescriptor = localVariablesManager.getBeforeInlineDescriptor(inlineMarker)
|
||||
val stackContentAfterInline = analyzer.getActualStack(inlineMarker)
|
||||
if (stackContentAfterInline != null && savedStackDescriptor.isNotEmpty()) {
|
||||
when (stackContentAfterInline.size) {
|
||||
1 -> {
|
||||
val returnValue = stackContentAfterInline.last()
|
||||
val returnValueLocalVarIndex = localVariablesManager.createReturnValueVariable(returnValue)
|
||||
actions.add({
|
||||
restoreStackWithReturnValue(methodNode, inlineMarker, savedStackDescriptor,
|
||||
returnValue, returnValueLocalVarIndex)
|
||||
})
|
||||
}
|
||||
0 ->
|
||||
actions.add({ restoreStack(methodNode, inlineMarker, savedStackDescriptor) })
|
||||
else ->
|
||||
throw AssertionError("Inline method should not leave more than 1 value on stack")
|
||||
val afterInlineFrame = analyzer.getFrame(inlineMarker) as FixStackAnalyzer.FixStackFrame?
|
||||
if (afterInlineFrame != null && savedStackDescriptor.isNotEmpty()) {
|
||||
assert(afterInlineFrame.stackSize <= 1) { "Inline method should not leave more than 1 value on stack" }
|
||||
if (afterInlineFrame.stackSize == 1) {
|
||||
val afterInlineStackValues = afterInlineFrame.getStackContent()
|
||||
val returnValue = afterInlineStackValues.last()
|
||||
val returnValueLocalVarIndex = localVariablesManager.createReturnValueVariable(returnValue)
|
||||
actions.add({
|
||||
restoreStackWithReturnValue(methodNode, inlineMarker, savedStackDescriptor,
|
||||
returnValue, returnValueLocalVarIndex)
|
||||
})
|
||||
}
|
||||
else {
|
||||
actions.add({ restoreStack(methodNode, inlineMarker, savedStackDescriptor) })
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -188,7 +181,7 @@ class FixStackMethodTransformer : MethodTransformer() {
|
||||
inlineMarker: AbstractInsnNode,
|
||||
localVariablesManager: LocalVariablesManager
|
||||
) {
|
||||
val savedStackValues = analyzer.getStackToSpill(inlineMarker)
|
||||
val savedStackValues = analyzer.savedStacks[inlineMarker]
|
||||
if (savedStackValues != null) {
|
||||
val savedStackDescriptor = localVariablesManager.allocateVariablesForBeforeInlineMarker(inlineMarker, savedStackValues)
|
||||
actions.add({ saveStack(methodNode, inlineMarker, savedStackDescriptor, false) })
|
||||
|
||||
@@ -115,10 +115,11 @@ fun replaceAlwaysTrueIfeqWithGoto(methodNode: MethodNode, node: AbstractInsnNode
|
||||
}
|
||||
}
|
||||
|
||||
fun replaceMarkerWithPops(methodNode: MethodNode, node: AbstractInsnNode, expectedStackSize: Int, stackContent: List<BasicValue>) {
|
||||
fun replaceMarkerWithPops(methodNode: MethodNode, node: AbstractInsnNode, expectedStackSize: Int, frame: Frame<BasicValue>) {
|
||||
with (methodNode.instructions) {
|
||||
for (stackValue in stackContent.subList(expectedStackSize, stackContent.size)) {
|
||||
insert(node, getPopInstruction(stackValue))
|
||||
while (frame.stackSize > expectedStackSize) {
|
||||
val top = frame.pop()
|
||||
insertBefore(node, getPopInstruction(top))
|
||||
}
|
||||
remove(node)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.codegen.signature;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil;
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmDescriptorTypeWriter;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
|
||||
@@ -58,7 +57,7 @@ public class JvmSignatureWriter extends JvmDescriptorTypeWriter<Type> {
|
||||
return;
|
||||
case Type.ARRAY:
|
||||
writeArrayType();
|
||||
writeAsmType(AsmUtil.correctElementType(asmType));
|
||||
writeAsmType(asmType.getElementType());
|
||||
writeArrayEnd();
|
||||
return;
|
||||
default:
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.KotlinToJvmSignatureMapper
|
||||
class KotlinToJvmSignatureMapperImpl : KotlinToJvmSignatureMapper {
|
||||
// We use empty BindingContext, because it is only used by KotlinTypeMapper for purposes irrelevant to the needs of this class
|
||||
private val typeMapper = KotlinTypeMapper(BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES, NoResolveFileClassesProvider,
|
||||
IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME, false, false)
|
||||
IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME, false)
|
||||
|
||||
override fun mapToJvmMethodSignature(function: FunctionDescriptor) = typeMapper.mapAsmMethod(function)
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ class BuilderFactoryForDuplicateSignatureDiagnostics(
|
||||
|
||||
// Avoid errors when some classes are not loaded for some reason
|
||||
private val typeMapper = KotlinTypeMapper(
|
||||
bindingContext, ClassBuilderMode.LIGHT_CLASSES, fileClassesProvider, IncompatibleClassTracker.DoNothing, moduleName, false, false
|
||||
bindingContext, ClassBuilderMode.LIGHT_CLASSES, fileClassesProvider, IncompatibleClassTracker.DoNothing, moduleName, false
|
||||
)
|
||||
private val reportDiagnosticsTasks = ArrayList<() -> Unit>()
|
||||
|
||||
|
||||
@@ -41,10 +41,12 @@ import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtScript
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.BindingTraceFilter
|
||||
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import java.io.File
|
||||
|
||||
@@ -92,7 +94,6 @@ class GenerationState @JvmOverloads constructor(
|
||||
val incrementalCacheForThisTarget: IncrementalCache?
|
||||
val packagesWithObsoleteParts: Set<FqName>
|
||||
val obsoleteMultifileClasses: List<FqName>
|
||||
val deserializationConfiguration: DeserializationConfiguration = CompilerDeserializationConfiguration(configuration)
|
||||
|
||||
init {
|
||||
val icComponents = configuration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS)
|
||||
@@ -124,7 +125,6 @@ class GenerationState @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
val isJvm8Target: Boolean = configuration.get(JVMConfigurationKeys.JVM_TARGET) == JvmTarget.JVM_1_8
|
||||
val isJvm8TargetWithDefaults: Boolean = isJvm8Target && configuration.getBoolean(JVMConfigurationKeys.JVM8_TARGET_WITH_DEFAULTS)
|
||||
val generateDefaultImplsForJvm8: Boolean = configuration.getBoolean(JVMConfigurationKeys.INTERFACE_COMPATIBILITY)
|
||||
|
||||
val moduleName: String = moduleName ?: JvmCodegenUtil.getModuleName(module)
|
||||
@@ -134,7 +134,7 @@ class GenerationState @JvmOverloads constructor(
|
||||
val bindingContext: BindingContext = bindingTrace.bindingContext
|
||||
val typeMapper: KotlinTypeMapper = KotlinTypeMapper(
|
||||
this.bindingContext, classBuilderMode, fileClassesProvider, IncompatibleClassTrackerImpl(extraJvmDiagnosticsTrace),
|
||||
this.moduleName, isJvm8Target, isJvm8TargetWithDefaults
|
||||
this.moduleName, isJvm8Target
|
||||
)
|
||||
val intrinsics: IntrinsicMethods = IntrinsicMethods()
|
||||
val samWrapperClasses: SamWrapperClasses = SamWrapperClasses(this)
|
||||
@@ -166,7 +166,7 @@ class GenerationState @JvmOverloads constructor(
|
||||
|
||||
val generateParametersMetadata: Boolean = configuration.getBoolean(JVMConfigurationKeys.PARAMETERS_METADATA)
|
||||
|
||||
val languageVersionSettings = configuration.languageVersionSettings
|
||||
val languageVersionSettings = configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS, LanguageVersionSettingsImpl.DEFAULT)
|
||||
val shouldInlineConstVals = languageVersionSettings.supportsFeature(LanguageFeature.InlineConstVals)
|
||||
|
||||
init {
|
||||
|
||||
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor;
|
||||
import org.jetbrains.kotlin.codegen.*;
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.kotlin.codegen.binding.MutableClosure;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
||||
import org.jetbrains.kotlin.codegen.signature.AsmTypeFactory;
|
||||
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
|
||||
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
|
||||
@@ -54,7 +53,10 @@ import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageFragment;
|
||||
import org.jetbrains.kotlin.load.kotlin.*;
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider.IncrementalMultifileClassPackageFragment;
|
||||
import org.jetbrains.kotlin.name.*;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.name.SpecialNames;
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
@@ -99,7 +101,6 @@ public class KotlinTypeMapper {
|
||||
private final IncompatibleClassTracker incompatibleClassTracker;
|
||||
private final String moduleName;
|
||||
private final boolean isJvm8Target;
|
||||
private final boolean isJvm8TargetWithDefaults;
|
||||
|
||||
private final TypeMappingConfiguration<Type> typeMappingConfiguration = new TypeMappingConfiguration<Type>() {
|
||||
private final Function2<String, String, String> defaultClassNameFactory
|
||||
@@ -155,8 +156,7 @@ public class KotlinTypeMapper {
|
||||
@NotNull JvmFileClassesProvider fileClassesProvider,
|
||||
@NotNull IncompatibleClassTracker incompatibleClassTracker,
|
||||
@NotNull String moduleName,
|
||||
boolean isJvm8Target,
|
||||
boolean isJvm8TargetWithDefaults
|
||||
boolean isJvm8Target
|
||||
) {
|
||||
this.bindingContext = bindingContext;
|
||||
this.classBuilderMode = classBuilderMode;
|
||||
@@ -164,7 +164,6 @@ public class KotlinTypeMapper {
|
||||
this.incompatibleClassTracker = incompatibleClassTracker;
|
||||
this.moduleName = moduleName;
|
||||
this.isJvm8Target = isJvm8Target;
|
||||
this.isJvm8TargetWithDefaults = isJvm8TargetWithDefaults;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -378,10 +377,6 @@ public class KotlinTypeMapper {
|
||||
return Type.VOID_TYPE;
|
||||
}
|
||||
|
||||
if (CoroutineCodegenUtilKt.isSuspendFunctionNotSuspensionView(descriptor)) {
|
||||
return mapReturnType(CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView((SimpleFunctionDescriptor) descriptor), sw);
|
||||
}
|
||||
|
||||
if (TypeSignatureMappingKt.hasVoidReturnType(descriptor)) {
|
||||
if (sw != null) {
|
||||
sw.writeAsmType(Type.VOID_TYPE);
|
||||
@@ -608,7 +603,7 @@ public class KotlinTypeMapper {
|
||||
|
||||
mapType(argument.getType(), signatureVisitor,
|
||||
argumentMode.toGenericArgumentMode(
|
||||
UtilsKt.getEffectiveVariance(parameter.getVariance(), argument.getProjectionKind())));
|
||||
TypeMappingUtil.getEffectiveVariance(parameter.getVariance(), argument.getProjectionKind())));
|
||||
|
||||
signatureVisitor.writeTypeArgumentEnd();
|
||||
}
|
||||
@@ -634,7 +629,7 @@ public class KotlinTypeMapper {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Variance getVarianceForWildcard(
|
||||
private static Variance getVarianceForWildcard(
|
||||
@NotNull TypeParameterDescriptor parameter,
|
||||
@NotNull TypeProjection projection,
|
||||
@NotNull TypeMappingMode mode
|
||||
@@ -690,7 +685,7 @@ public class KotlinTypeMapper {
|
||||
descriptor = classCallable;
|
||||
continue;
|
||||
}
|
||||
else if (isSuperCall && !isJvm8TargetWithDefaults && !isInterface(descriptor.getContainingDeclaration())) {
|
||||
else if (isSuperCall && !isJvm8Target && !isInterface(descriptor.getContainingDeclaration())) {
|
||||
//Don't unwrap fake overrides from class to interface cause substituted override would be implicitly generated for target 1.6
|
||||
return descriptor;
|
||||
}
|
||||
@@ -710,7 +705,7 @@ public class KotlinTypeMapper {
|
||||
JvmMethodSignature method = mapSignatureSkipGeneric(descriptor);
|
||||
Type owner = mapClass(((ClassConstructorDescriptor) descriptor).getContainingDeclaration());
|
||||
String defaultImplDesc = mapDefaultMethod(descriptor, OwnerKind.IMPLEMENTATION).getDescriptor();
|
||||
return new CallableMethod(owner, owner, defaultImplDesc, method, INVOKESPECIAL, null, null, null, false);
|
||||
return new CallableMethod(owner, owner, defaultImplDesc, method, INVOKESPECIAL, null, null, null);
|
||||
}
|
||||
|
||||
if (descriptor instanceof LocalVariableAccessorDescriptor) {
|
||||
@@ -730,7 +725,6 @@ public class KotlinTypeMapper {
|
||||
FunctionDescriptor baseMethodDescriptor;
|
||||
int invokeOpcode;
|
||||
Type thisClass;
|
||||
boolean isInterfaceMember = false;
|
||||
|
||||
if (functionParent instanceof ClassDescriptor) {
|
||||
FunctionDescriptor declarationFunctionDescriptor = findAnyDeclaration(functionDescriptor);
|
||||
@@ -746,16 +740,15 @@ public class KotlinTypeMapper {
|
||||
baseMethodDescriptor = findBaseDeclaration(functionDescriptor).getOriginal();
|
||||
ClassDescriptor ownerForDefault = (ClassDescriptor) baseMethodDescriptor.getContainingDeclaration();
|
||||
ownerForDefaultImpl =
|
||||
isJvmInterface(ownerForDefault) && !isJvm8InterfaceWithDefaults(ownerForDefault) ?
|
||||
isJvmInterface(ownerForDefault) && !isJvm8Interface(ownerForDefault) ?
|
||||
mapDefaultImpls(ownerForDefault) : mapClass(ownerForDefault);
|
||||
|
||||
if (isInterface && (superCall || descriptor.getVisibility() == Visibilities.PRIVATE || isAccessor(descriptor))) {
|
||||
thisClass = mapClass(currentOwner);
|
||||
if (declarationOwner instanceof JavaClassDescriptor || isJvm8InterfaceWithDefaults(declarationOwner)) {
|
||||
if (declarationOwner instanceof JavaClassDescriptor || isJvm8Interface(declarationOwner)) {
|
||||
invokeOpcode = INVOKESPECIAL;
|
||||
signature = mapSignatureSkipGeneric(functionDescriptor);
|
||||
owner = thisClass;
|
||||
isInterfaceMember = true;
|
||||
}
|
||||
else {
|
||||
invokeOpcode = INVOKESTATIC;
|
||||
@@ -770,16 +763,13 @@ public class KotlinTypeMapper {
|
||||
CodegenUtilKt.isJvmStaticInObjectOrClass(functionDescriptor);
|
||||
if (isStaticInvocation) {
|
||||
invokeOpcode = INVOKESTATIC;
|
||||
isInterfaceMember = currentIsInterface && currentOwner instanceof JavaClassDescriptor;
|
||||
}
|
||||
else if (isInterface) {
|
||||
invokeOpcode = INVOKEINTERFACE;
|
||||
isInterfaceMember = true;
|
||||
}
|
||||
else {
|
||||
boolean isPrivateFunInvocation = Visibilities.isPrivate(functionDescriptor.getVisibility());
|
||||
invokeOpcode = superCall || isPrivateFunInvocation ? INVOKESPECIAL : INVOKEVIRTUAL;
|
||||
isInterfaceMember = superCall && currentIsInterface;
|
||||
}
|
||||
|
||||
FunctionDescriptor overriddenSpecialBuiltinFunction =
|
||||
@@ -831,13 +821,11 @@ public class KotlinTypeMapper {
|
||||
|
||||
return new CallableMethod(
|
||||
owner, ownerForDefaultImpl, defaultImplDesc, signature, invokeOpcode,
|
||||
thisClass, receiverParameterType, calleeType,
|
||||
isJvm8Target ? isInterfaceMember : invokeOpcode == INVOKEINTERFACE );
|
||||
thisClass, receiverParameterType, calleeType);
|
||||
}
|
||||
|
||||
private boolean isJvm8InterfaceWithDefaults(@NotNull ClassDescriptor ownerForDefault) {
|
||||
return isJvmInterface(ownerForDefault) &&
|
||||
JvmCodegenUtil.isJvm8InterfaceWithDefaults(ownerForDefault, isJvm8Target, isJvm8TargetWithDefaults);
|
||||
private boolean isJvm8Interface(@NotNull ClassDescriptor ownerForDefault) {
|
||||
return isJvmInterface(ownerForDefault) && JvmCodegenUtil.isJvm8Interface(ownerForDefault, isJvm8Target);
|
||||
}
|
||||
|
||||
public static boolean isAccessor(@NotNull CallableMemberDescriptor descriptor) {
|
||||
@@ -959,7 +947,7 @@ public class KotlinTypeMapper {
|
||||
if (!(descriptor instanceof ConstructorDescriptor) &&
|
||||
descriptor.getVisibility() == Visibilities.INTERNAL &&
|
||||
!descriptor.getAnnotations().hasAnnotation(KotlinBuiltIns.FQ_NAMES.publishedApi)) {
|
||||
return name + "$" + NameUtils.sanitizeAsJavaIdentifier(moduleName);
|
||||
return name + "$" + JvmAbi.sanitizeAsJavaIdentifier(moduleName);
|
||||
}
|
||||
|
||||
return name;
|
||||
@@ -1027,10 +1015,6 @@ public class KotlinTypeMapper {
|
||||
}
|
||||
}
|
||||
|
||||
if (CoroutineCodegenUtilKt.isSuspendFunctionNotSuspensionView(f)) {
|
||||
return mapSignature(CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(f), kind, skipGenericSignature);
|
||||
}
|
||||
|
||||
if (f instanceof ConstructorDescriptor) {
|
||||
return mapSignature(f, kind, f.getOriginal().getValueParameters(), skipGenericSignature);
|
||||
}
|
||||
@@ -1154,13 +1138,13 @@ public class KotlinTypeMapper {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getDefaultDescriptor(
|
||||
@NotNull Method method,
|
||||
@Nullable String dispatchReceiverDescriptor,
|
||||
@NotNull CallableDescriptor callableDescriptor
|
||||
) {
|
||||
private static String getDefaultDescriptor(@NotNull Method method, @Nullable String dispatchReceiverDescriptor, boolean isExtension) {
|
||||
String descriptor = method.getDescriptor();
|
||||
int maskArgumentsCount = (callableDescriptor.getValueParameters().size() + Integer.SIZE - 1) / Integer.SIZE;
|
||||
int argumentsCount = Type.getArgumentTypes(descriptor).length;
|
||||
if (isExtension) {
|
||||
argumentsCount--;
|
||||
}
|
||||
int maskArgumentsCount = (argumentsCount + Integer.SIZE - 1) / Integer.SIZE;
|
||||
String additionalArgs = StringUtil.repeat(Type.INT_TYPE.getDescriptor(), maskArgumentsCount);
|
||||
additionalArgs += (isConstructor(method) ? DEFAULT_CONSTRUCTOR_MARKER : OBJECT_TYPE).getDescriptor();
|
||||
String result = descriptor.replace(")", additionalArgs + ")");
|
||||
@@ -1186,7 +1170,7 @@ public class KotlinTypeMapper {
|
||||
String descriptor = getDefaultDescriptor(
|
||||
jvmSignature,
|
||||
isStaticMethod(kind, functionDescriptor) || isConstructor ? null : ownerType.getDescriptor(),
|
||||
CodegenUtilKt.unwrapFrontendVersion(functionDescriptor)
|
||||
functionDescriptor.getExtensionReceiverParameter() != null
|
||||
);
|
||||
|
||||
return new Method(isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, descriptor);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package org.jetbrains.kotlin.codegen.state
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES as BUILTIN_NAMES
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
||||
@@ -29,8 +30,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.getEffectiveVariance
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES as BUILTIN_NAMES
|
||||
|
||||
fun KotlinType.isMostPreciseContravariantArgument(parameter: TypeParameterDescriptor): Boolean =
|
||||
// TODO: probably class upper bound should be used
|
||||
@@ -60,6 +59,22 @@ private fun KotlinType.canHaveSubtypesIgnoringNullability(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
fun getEffectiveVariance(parameterVariance: Variance, projectionKind: Variance): Variance {
|
||||
if (parameterVariance === Variance.INVARIANT) {
|
||||
return projectionKind
|
||||
}
|
||||
if (projectionKind === Variance.INVARIANT) {
|
||||
return parameterVariance
|
||||
}
|
||||
if (parameterVariance === projectionKind) {
|
||||
return parameterVariance
|
||||
}
|
||||
|
||||
// In<out X> = In<*>
|
||||
// Out<in X> = Out<*>
|
||||
return Variance.OUT_VARIANCE
|
||||
}
|
||||
|
||||
val CallableDescriptor?.isMethodWithDeclarationSiteWildcards: Boolean
|
||||
get() {
|
||||
if (this !is CallableMemberDescriptor) return false
|
||||
@@ -75,7 +90,7 @@ private val METHODS_WITH_DECLARATION_SITE_WILDCARDS = setOf(
|
||||
BUILTIN_NAMES.mutableMap.child("putAll")
|
||||
)
|
||||
|
||||
fun TypeMappingMode.updateArgumentModeFromAnnotations(type: KotlinType): TypeMappingMode {
|
||||
internal fun TypeMappingMode.updateArgumentModeFromAnnotations(type: KotlinType): TypeMappingMode {
|
||||
type.suppressWildcardsMode()?.let {
|
||||
return TypeMappingMode.createWithConstantDeclarationSiteWildcardsMode(
|
||||
skipDeclarationSiteWildcards = it, isForAnnotationParameter = isForAnnotationParameter)
|
||||
|
||||
@@ -34,7 +34,7 @@ public class EnumSwitchCodegen extends SwitchCodegen {
|
||||
@NotNull ExpressionCodegen codegen,
|
||||
@NotNull WhenByEnumsMapping mapping
|
||||
) {
|
||||
super(expression, isStatement, isExhaustive, codegen, codegen.getState().getTypeMapper().mapType(mapping.getEnumClassDescriptor()));
|
||||
super(expression, isStatement, isExhaustive, codegen);
|
||||
this.mapping = mapping;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ public class IntegralConstantsSwitchCodegen extends SwitchCodegen {
|
||||
boolean isExhaustive,
|
||||
@NotNull ExpressionCodegen codegen
|
||||
) {
|
||||
super(expression, isStatement, isExhaustive, codegen, null);
|
||||
super(expression, isStatement, isExhaustive, codegen);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -43,7 +43,7 @@ public class StringSwitchCodegen extends SwitchCodegen {
|
||||
boolean isExhaustive,
|
||||
@NotNull ExpressionCodegen codegen
|
||||
) {
|
||||
super(expression, isStatement, isExhaustive, codegen, null);
|
||||
super(expression, isStatement, isExhaustive, codegen);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
package org.jetbrains.kotlin.codegen.when;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.kotlin.codegen.FrameMap;
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings;
|
||||
import org.jetbrains.kotlin.psi.KtWhenEntry;
|
||||
import org.jetbrains.kotlin.psi.KtWhenExpression;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
@@ -51,8 +51,7 @@ abstract public class SwitchCodegen {
|
||||
|
||||
public SwitchCodegen(
|
||||
@NotNull KtWhenExpression expression, boolean isStatement,
|
||||
boolean isExhaustive, @NotNull ExpressionCodegen codegen,
|
||||
@Nullable Type subjectType
|
||||
boolean isExhaustive, @NotNull ExpressionCodegen codegen
|
||||
) {
|
||||
this.expression = expression;
|
||||
this.isStatement = isStatement;
|
||||
@@ -60,7 +59,7 @@ abstract public class SwitchCodegen {
|
||||
this.codegen = codegen;
|
||||
this.bindingContext = codegen.getBindingContext();
|
||||
|
||||
this.subjectType = subjectType != null ? subjectType : codegen.expressionType(expression.getSubjectExpression());
|
||||
subjectType = codegen.expressionType(expression.getSubjectExpression());
|
||||
resultType = isStatement ? Type.VOID_TYPE : codegen.expressionType(expression);
|
||||
v = codegen.v;
|
||||
}
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.KotlinCompilerVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion
|
||||
import org.jetbrains.kotlin.load.kotlin.DeserializedDescriptorResolver
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.org.objectweb.asm.AnnotationVisitor
|
||||
@@ -37,7 +37,7 @@ fun writeKotlinMetadata(
|
||||
av.visit(JvmAnnotationNames.BYTECODE_VERSION_FIELD_NAME, JvmBytecodeBinaryVersion.INSTANCE.toArray())
|
||||
av.visit(JvmAnnotationNames.KIND_FIELD_NAME, kind.id)
|
||||
var flags = extraFlags
|
||||
if (KotlinCompilerVersion.isPreRelease() && state.languageVersionSettings.languageVersion == LanguageVersion.LATEST) {
|
||||
if (DeserializedDescriptorResolver.IS_PRE_RELEASE && state.languageVersionSettings.languageVersion == LanguageVersion.LATEST) {
|
||||
flags = flags or JvmAnnotationNames.METADATA_PRE_RELEASE_FLAG
|
||||
}
|
||||
if (flags != 0) {
|
||||
|
||||
@@ -134,7 +134,7 @@ open class MetadataSerializer(private val dependOnOldBuiltIns: Boolean) {
|
||||
|
||||
private fun getPackageFilePath(packageFqName: FqName, fileName: String): String =
|
||||
packageFqName.asString().replace('.', '/') + "/" +
|
||||
PackagePartClassUtils.getFilePartShortName(fileName) + DOT_METADATA_FILE_EXTENSION
|
||||
PackagePartClassUtils.getPartClassName(fileName.substringBeforeLast(".kt")) + DOT_METADATA_FILE_EXTENSION
|
||||
|
||||
private fun getClassFilePath(classId: ClassId): String =
|
||||
classId.asSingleFqName().asString().replace('.', '/') + DOT_METADATA_FILE_EXTENSION
|
||||
|
||||
@@ -18,8 +18,6 @@ package org.jetbrains.kotlin.serialization.builtins
|
||||
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import org.jetbrains.kotlin.builtins.BuiltInSerializerProtocol
|
||||
import org.jetbrains.kotlin.builtins.JvmBuiltInClassDescriptorFactory
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.messages.*
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
@@ -28,16 +26,12 @@ import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.addKotlinSourceRoots
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.serialization.MetadataSerializer
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import java.io.File
|
||||
|
||||
class BuiltInsSerializer(dependOnOldBuiltIns: Boolean) : MetadataSerializer(dependOnOldBuiltIns) {
|
||||
@@ -94,21 +88,11 @@ class BuiltInsSerializer(dependOnOldBuiltIns: Boolean) : MetadataSerializer(depe
|
||||
fqName ->
|
||||
val packageView = module.getPackage(fqName)
|
||||
PackageSerializer(
|
||||
packageView.memberScope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS) + createCloneable(module),
|
||||
packageView.memberScope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS),
|
||||
packageView.fragments.flatMap { fragment -> DescriptorUtils.getAllDescriptors(fragment.getMemberScope()) },
|
||||
packageView.fqName,
|
||||
File(destDir, BuiltInSerializerProtocol.getBuiltInsFilePath(packageView.fqName))
|
||||
).run()
|
||||
}
|
||||
}
|
||||
|
||||
// Serialize metadata for kotlin.Cloneable manually for compatibility with kotlin-reflect 1.0 which expects this metadata to be there.
|
||||
// Since Kotlin 1.1, we always discard this class during deserialization (see ClassDeserializer.kt).
|
||||
private fun createCloneable(module: ModuleDescriptor): ClassDescriptor {
|
||||
val factory = JvmBuiltInClassDescriptorFactory(LockBasedStorageManager.NO_LOCKS, module) {
|
||||
EmptyPackageFragmentDescriptor(module, KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME)
|
||||
}
|
||||
return factory.createClass(ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.cloneable.toSafe()))
|
||||
?: error("Could not create kotlin.Cloneable in $module")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,9 @@ import com.intellij.util.SmartList;
|
||||
import com.sampullara.cli.Argument;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class CommonCompilerArguments implements Serializable {
|
||||
public static final long serialVersionUID = 0L;
|
||||
|
||||
public abstract class CommonCompilerArguments {
|
||||
public static final String PLUGIN_OPTION_FORMAT = "plugin:<pluginId>:<optionName>=<value>";
|
||||
|
||||
@GradleOption(DefaultValues.LanguageVersions.class)
|
||||
@@ -63,12 +60,6 @@ public abstract class CommonCompilerArguments implements Serializable {
|
||||
@ValueDescription("<count>")
|
||||
public String repeat;
|
||||
|
||||
@Argument(value = "Xskip-metadata-version-check", description = "Load classes with bad metadata version anyway (incl. pre-release classes)")
|
||||
public boolean skipMetadataVersionCheck;
|
||||
|
||||
@Argument(value = "Xallow-kotlin-package", description = "Allow compiling code in package 'kotlin'")
|
||||
public boolean allowKotlinPackage;
|
||||
|
||||
@Argument(value = "Xplugin", description = "Load plugins from the given classpath")
|
||||
@ValueDescription("<path>")
|
||||
public String[] pluginClasspaths;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user