Compare commits

...

458 Commits

Author SHA1 Message Date
Sergey Bogolepov
a7fd140329 [K/N] Separate compilation POC 2021-08-09 10:28:17 +07:00
Sergey Bogolepov
4bfa5ad532 wip 2021-08-07 11:47:02 +07:00
Sergey Bogolepov
b694fcdac6 wip 2021-08-07 11:46:47 +07:00
Sergey Bogolepov
b991d3cd4c wip 2021-08-07 11:46:37 +07:00
Sergey Bogolepov
f95c1a0996 [K/N] Rename lldLocation to linker
Actually, there is nothing LLD-specific in this property now,
so let's rename it to avoid confusion.
2021-08-07 11:45:55 +07:00
Sergey Bogolepov
216e306e58 [K/N] Invoke MinGW linker directly
There is an overhead of invoking linker via `clang -fuse-ld`. It became
significant in LLVM 11.1.0. Let's avoid it by invoking LLD directly.
2021-08-07 11:45:54 +07:00
Sergey Bogolepov
1b6ff4d8bd wip 2021-08-07 11:20:11 +07:00
Sergey Bogolepov
65358742dd Working with compiler caches 2021-08-07 11:20:11 +07:00
Sergey Bogolepov
e05c139668 brr 2021-08-07 11:20:11 +07:00
Sergey Bogolepov
d7283d2983 brr 2021-08-07 11:20:10 +07:00
Jinseong Jeon
59ad7e0e04 FIR IDE: create call target for super reference 2021-08-04 15:10:04 +02:00
Jinseong Jeon
c597ee0e34 FIR IDE: fix kotlin origin of annotation call 2021-08-04 15:10:03 +02:00
Jinseong Jeon
c559adc0fb FIR IDE: render list of symbols with indentation
Also, render `psi` of annotation call
(to showcase they're always null for now)
2021-08-04 15:10:02 +02:00
Jinseong Jeon
5b40f291bd FIR IDE: resolve KtTypeReference from super type entry to KtType
which will be mapped to delegated constructor call where we can still
find the referred type.
2021-08-04 15:09:58 +02:00
Jinseong Jeon
d4e1ecd9d3 FIR IDE: fix scope processing for enum entry with members 2021-08-04 15:09:57 +02:00
Stanislav Erokhin
748a2d2e7c [MPP] Performance optimization in expect/actual checker
Previously, the checker executed for every declaration i.e. every
declaration was considered as expect declaration. Because of that in
some cases this checker could eat 6% of compilation time.
After this commit only declarations marked with expect or actual
are checked. To achieve that, logic, that do reporting about missing
actual modifier was moved to the Actual part.

Please note, that in cases where there is no expect/actual modifier at
all other errors (like redeclaration and missing body on "actual"
declaration) would be reported.

Useful nodes:
- In this checker reportOn is always the same as
descriptor.sourceElement.ktElement. This is because the only case when
it isn't true is PropertyAccessors and they are filtered
- Annotation constructor descriptor isActual == true all the time
- previously for weak incompatible members ACTUAL_MISSING
was not reported
- the logic here is super complicated and crazy, but I don't think that
there is sense to refactor it in the old FE
2021-08-04 15:19:34 +03:00
Stanislav Erokhin
e9a2997f7e Minor refactoring -- use util function 2021-08-04 15:19:32 +03:00
Andrey Zinovyev
cea6081d36 [FIR] LT positioning strategy for UNREACHABLE_CODE 2021-08-04 14:42:24 +03:00
Andrey Zinovyev
ec4cbfef59 [FIR] UNREACHABLE_CODE diagnostic (wip)
Implementation for PSI only
2021-08-04 14:42:24 +03:00
Elena Lepilkina
dcd61c292d [K/N][perf] Fix kotlin language version in kotlin-dsl plugin for performance subproject 2021-08-04 10:39:53 +00:00
Sergey Bogolepov
d5e2ac0efc Fix KotlinLibraryResolverImpl.kt on Windows
`absoluteFile` is not enough to make path unique. For example, it doesn't
expand things like '..' and 'IDEAPR~1' on Windows. `canonicalFile` seems
to solve the problem.
2021-08-04 05:44:27 +00:00
Ivan Kochurkin
3c3e51c6de [FIR] Temporary change TYPE_VARIANCE_CONFLICT to warning to unblock bootstrap tests 2021-08-04 01:04:22 +03:00
Ivan Kochurkin
5291648d39 [FIR] Temporary change UPPER_BOUND_VIOLATED to warning to unblock bootstrap tests 2021-08-03 23:15:40 +03:00
Dmitry Petrov
bd71fbe982 JVM_IR KT-34594 strip fake variable initialization during inlining 2021-08-03 20:41:31 +03:00
Dmitry Petrov
37050e0616 JVM_IR KT-34594 don't generate fake local variable for @InlineOnly 2021-08-03 20:41:31 +03:00
Simon Ogorodnik
32b380e187 [FP] Fix compiler arguments for intellij-community building 2021-08-03 19:52:23 +03:00
Simon Ogorodnik
872b6b7e81 [FE 1.0 FP] Fix compiler arguments to avoid errors 2021-08-03 19:52:23 +03:00
Simon Ogorodnik
a7961a4a45 [FIR MT] Add reading of packagePrefix from model of java roots 2021-08-03 19:52:22 +03:00
Simon Ogorodnik
97bfc49ed6 [FIR Test] Fix file counting for global passes 2021-08-03 19:52:21 +03:00
Simon Ogorodnik
1188d311b3 [FIR MT] Add sorting by timestamp from model, reading of modularJdkRoot 2021-08-03 19:52:20 +03:00
Mikhail Glukhikh
77f0bd3834 FirOuterClassArgumentsRequiredChecker: read containingClass safely 2021-08-03 19:52:18 +03:00
Nikolay Krasko
bb718f2e0b Allow reading signing parameters from environment variables (KTI-552) 2021-08-03 17:54:09 +03:00
Denis.Zharkov
fa9f0d588d Optimize FastJarHandler
- Do not use normalization as it seems unnecessary
2021-08-03 16:24:51 +03:00
Denis.Zharkov
2266a348c3 Get rid of another map built in FastJarHandler 2021-08-03 16:24:50 +03:00
Denis.Zharkov
42b2605c2a Minor. Rename local vals 2021-08-03 16:24:50 +03:00
Denis.Zharkov
1a262c9c31 Adapt FastJarVirtualFile constructor to its usages 2021-08-03 16:24:49 +03:00
Denis.Zharkov
920d57563b Add fast-path for filename String creation
In most cases, it's encoded with ASCI
2021-08-03 16:24:48 +03:00
Denis.Zharkov
cd51264940 Avoid using FactoryMap at FastJarHandler
It has quite a slow entrySet implementation
2021-08-03 16:24:48 +03:00
Denis.Zharkov
979f5e8443 Rework FastJarHandler
1. Do not inherit from ZipHandler
2. Previously, the following computations have been happening:
- Map<String, ZipEntryDescription> -> Map<String, EntryInfo> (see createEntriesMap)
- Map<String, EntryInfo> -> VirtualFile tree

But the intermediate computations (Map<String, EntryInfo>)
were only used in the constructor, thus they've eliminated in this commit

3. Unclear magic semantic from `getOrCreate` with "/" and "\\" (copy-pasted from CoreJarHandler)
has been replaced with `normalizePath`
2021-08-03 16:24:47 +03:00
Denis.Zharkov
edf9f5e647 FIR: Minor. Clarify name for containingClassForStaticMemberAttr 2021-08-03 16:24:46 +03:00
Denis.Zharkov
956bf22191 FIR: Optimize AbstractAnnotationDeserializer
Do not search for annotation constructors unless we really need it
2021-08-03 16:24:45 +03:00
Viacheslav Kormushkin
1654824467 Commonization of CocoaPods libraries
#KT-41631
2021-08-03 12:50:05 +00:00
Pavel Punegov
73bb6d5d34 [Native] Move JavaLauncher property from global scope to the KonanPlugin 2021-08-03 10:15:08 +00:00
Pavel Punegov
6bbfe0d503 [Native] Add project property that holds JavaLauncher provider
This property is initialized once to make ToolRunner do not query for
the launcher. Also set JDK 11 as a default in case of an unavailable JDK
set as the toolchain, like JDK 17 that is not available in the auto mode
in Gradle and requires environment variable to be set.
2021-08-03 10:15:08 +00:00
Pavel Punegov
2656c94535 [Native] Use common toolchain configuration 2021-08-03 10:15:08 +00:00
Pavel Punegov
ba5bd0b069 [Native] Add java plugin dependency to Konan plugin
Change required version of Gradle to 6.7
2021-08-03 10:15:07 +00:00
Pavel Punegov
ad2fabb7cb Add environments for JDK 16 and 17 2021-08-03 10:15:07 +00:00
Pavel Punegov
afa8e16c25 [Native] JDK toolchains in KonanToolRunner
Use JDK toolchains in KonanToolRunner to make build able to change JDK
Use JDK 17 for MacOS aarch64 hosts
2021-08-03 10:15:06 +00:00
Pavel Punegov
5338705402 [Native] Enable parallel platform libs generation on parameter
Use kotlin.native.platformLibs.parallel to control parallel generation.
Disable parallel execution of platform libs on MacOS aarch64
2021-08-03 10:15:06 +00:00
Ilmir Usmanov
cbe0de6111 Extend local variable ranges
when it is safe. Otherwise, they will not be visible in
debugger as soon as they become dead.
 #KT-47749 Fixed
2021-08-03 08:00:51 +00:00
Dmitriy Novozhilov
ca9cbf7eb7 Fix warnings in K/Native code 2021-08-03 07:40:57 +00:00
Mikhael Bogdanov
0a5991d6e7 Update bootstrap to 1.6.0-dev-2117 2021-08-03 07:40:56 +00:00
Svyatoslav Scherbina
fb27459b2e Native: fix downloading dependencies when producing cache 2021-08-03 07:01:08 +00:00
Sergey Bogolepov
e177cecd50 [K/N] Specify -target-cpu for all targets
Motivation:
1. Avoid things like KT-47911.
2. Generate a bit more effective code in some cases.
3. A bit easier -Xoverride-konan-properties.
2021-08-03 05:54:36 +00:00
Sergey Bogolepov
b37cdae966 [K/N] Fix KT-47911
Specify target-cpu when compiling for AArch64 Darwin targets, because
Apple's CPU might execute "movi.2d vD, #0" incorrectly.

See https://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20171218/511205.html.
2021-08-03 05:54:35 +00:00
Sergey Bogolepov
84d06f35e9 [K/N] Update usages of LLVM bin directory on Windows 2021-08-03 05:42:09 +00:00
Sergey Bogolepov
7d8360f38b [K/N] Set target-features for host targets
Benchmarks on CI show that there are some performance regressions after
LLVM update due to worse inliner results. Explicit specification of
target-features fixes the problem. Interestingly, it seems that this is
not required for Darwin AArch64 target.
2021-08-03 05:42:08 +00:00
Sergey Bogolepov
adc1ca76f4 [K/N] Update requirements in readme
* Updated Windows requirements for building from source
* Removed Linux requirements on ncurses because LLVM is built without it
* Explicitly stated glibc version
2021-08-03 05:42:08 +00:00
Sergey Bogolepov
bfc3f35d94 [K/N] Disable stress_gc_allocations for watchos_simulator_arm64 2021-08-03 05:42:07 +00:00
Sergey Bogolepov
8803a69c9d [K/N] Add ARM Neon intrinsic to CallsChecker whitelist 2021-08-03 05:42:07 +00:00
Sergey Bogolepov
922fcc4049 [K/N] Fix windows dynamic tests for LLD
Adjust compilation and linking flags to workaround absence of direct
DLL linkage in LLD.
2021-08-03 05:42:07 +00:00
Sergey Bogolepov
c7c78e0e1a [K/N] Use LLD 12.0.1 for MinGW targets
Clang-produced and GCC-produced binaries might be ABI-incompatible on
MinGW. Explanation on GitHub: msys2/MINGW-packages/issues/6855#issuecomment-680859662.
TL;DR: GCC-generated sections are 16-byte-padded, while Clang ones are
not. It causes problems during merge of COMDAT sections.
I observed the problem during compilation of runtime tests, but it is
possible that the problem could affect main compilation pipeline as well.
https://reviews.llvm.org/D86659 (which landed in LLVM 12) fixes
the problem. So we have another motivation for switching to LLD besides
https://youtrack.jetbrains.com/issue/KT-47605.

The only known downside is unsupported defsym which causes slight binary
size increase. I think it is doable.
2021-08-03 05:42:06 +00:00
Sergey Bogolepov
6e093b0beb [K/N] Update libffi for Windows
MinGW and MSVC are hardly compatible in case of static linkage, so we
need to use a native libffi.
2021-08-03 05:42:06 +00:00
Sergey Bogolepov
a525f3f357 [K/N] Fix path to ld.gold on Windows
targetToolchain.mingw_x64-linux_* are changed, so we should their usages
Probably, we could switch to LLD, but it requires additional testing.
2021-08-03 05:42:05 +00:00
Sergey Bogolepov
66ddd15798 [K/N] Support compiler compilation in MSVC environment
The right way is to add something like KonanTarget.MSVC_X64, but doing
so requires changes throughout whole compiler. It would be especially
painful in HostManager, where we would need to deprecate
KonanTarget.MINGW_X64 as host. Instead we "hack" ClangArgs to compile
for x86_64-pc-windows-msvc instead of x86_64-pc-windows-gnu in JNI case.

CI may contain custom MSVC and Windows Kit installation path, so we
should support it. Things might break when machine has several MSVC
installed (at custom and default path), but it sounds more like
incorrect environment setup problem than ours.
2021-08-03 05:42:05 +00:00
Sergey Bogolepov
a78fcd6b64 [K/N] Separate ClangArgs for jni and native
Since LLVM for Windows is now native instead on MinGW, we have to
compile code in a different environment in case of JNI. This commits
just separates ClangArgs into two subclasses without actual behavior
changes.
2021-08-03 05:42:05 +00:00
Sergey Bogolepov
fbbbc1c092 [K/N] Drop Configurables interface for ClangArgs
ClangArgs abused delegation mechanism and it complicated its interface.
2021-08-03 05:42:04 +00:00
Sergey Bogolepov
a783ee9ae7 [K/N] Drop -D_GLIBCXX_USE_CXX11_ABI=0 for LLVM
We don't use old glibc++ ABI for LLVM, so this flag have to be dropped.
(Otherwise you'll find yourself fighting sporadic runtime crushes,
trust me).
2021-08-03 05:42:04 +00:00
Sergey Bogolepov
0d39442a5e [K/N] Update linux_arm32_hfp llvm target features
Set of target features has changed between LLVM 8 and LLVM 11.
Update the list for linux_arm32_hfp to make clang stop complaining.
2021-08-03 05:42:03 +00:00
Sergey Bogolepov
1c7a27ce42 [K/N] Fix mxgot flag for MIPS
It was dropped from cc1 interface, so use -target-feature +xgot instead.
2021-08-03 05:42:03 +00:00
Sergey Bogolepov
e8b025f267 [K/N] Drop obsolete --no-threads LLD flags
--no-threads flag was used, because LLD had deadlock long time ago.
This flag is removed from LLD (in favor of --threads=N) and it looks
like that the bug is gone now. So we can just drop --no-threads flag!
2021-08-03 05:42:03 +00:00
Sergey Bogolepov
572f08151a [K/N] Disable code coverage testing
Since LLVM 8, coverage format has changed.
We don't officially provide code coverage for end-users, so it's ok to
disable it for now and fix later.
2021-08-03 05:42:02 +00:00
Sergey Bogolepov
02aebd6565 [K/N] Update LLVM stubs to 11.1.0
Also add necessary changes to CoverageMappingC.cpp to make it compile.
2021-08-03 05:42:02 +00:00
Sergey Bogolepov
601465fa81 [K/N] Change how common polyhash function are included
Recent versions of LLVM complain when caller and callee have
different vector attributes: https://reviews.llvm.org/D82562.

To mitigate this problem this commit changes how we include
polyHashUnroll* and polyHashTail into Traits: we duplicate them
inside each trait with correct attributes by using
```
#pragma clang attribute push(ATTRIBUTE, apply_to = function)
```
This solution is not pretty for sure, but Clang is not complaining
anymore.
2021-08-03 05:42:02 +00:00
Sergey Bogolepov
493fa1c1e3 [K/N] Update Clang stubs for 11.1.0
Removed hacks for CXType_ExtVector type because now it is included in
Clang C API.
2021-08-03 05:42:01 +00:00
Sergey Bogolepov
023c775188 [K/N] Bump macOS minimal version 2021-08-03 05:42:01 +00:00
Sergey Bogolepov
7dda04a1c9 [K/N] Update LLVM distributions to 11.1.0
This commit is important for several reasons:
1. Finally, LLVM update from 8.0.0 to 11.1.0
At the time of writing, LLVM 12.0.0 already came out, but we need to be
compatible with LLVM from Xcode 12.5, so that's why we stick to a bit
older version of LLVM.
2. These LLVM distributions are built with tools/llvm_builder/package.py
We finally managed to introduce an explicit process of building our LLVM
distributions, so we will be able to updated them more frequently and
adapt to our needs.
3. Native Windows LLVM instead of MinGW
Last but not least, we now use native Windows LLVM distribution. While
it might be harder to use (no more posix everywhere), simpler build
process (building msys2 is not that easy) and no need for MinGW-specific
patches makes such distribution way more convenient.
2021-08-03 05:42:00 +00:00
Sergey Bogolepov
44256db824 [K/N] Update minimal Xcode version
The next LLVM version will be 11.1.0, and we need to be sure that
Xcode supports bitcode of this version. So we bump minimal Xcode version
to 12.5, which should be OK, because by the time Kotlin 1.6.0 comes out,
Xcode 12.5 will be around 6 month old.

Also this commit simplifies tarball naming.
2021-08-03 05:42:00 +00:00
Sergey Bogolepov
017c8d8211 [K/N] Drop linuxArm32Hfp from tetris sample
Its sysroot doesn't include SDL2 anymore, so it won't compile anyway.
2021-08-03 05:38:07 +00:00
Sergey Bogolepov
0923d13d55 [K/N] Fix gtk sample compilation on MinGW 2021-08-03 05:38:06 +00:00
Nikolay Krasko
6c49a18770 Fix exhaustive when in HierarchicalStructureOptOutIT.kt 2021-08-03 06:53:33 +03:00
Dmitriy Novozhilov
0ac96b4973 [Test] Remove redundant out variance from TestStep 2021-08-03 00:26:10 +03:00
Dmitriy Novozhilov
b584fed93d [FIR] Migrate warning/error pairs to DiagnosticFactoryForDeprecation 2021-08-03 00:20:11 +03:00
Dmitriy Novozhilov
adfeab1bd0 [FIR] Add ability to generate special diagnostic factories for deprecation warnings
This kind of diagnostic factory has two different factories with warning
  and error severity and language feature with turns on reporting of error
2021-08-03 00:17:33 +03:00
Dmitriy Novozhilov
d17f984edf [FE 1.0] Migrate most of warning/error pairs to DiagnosticFactoryForDeprecation 2021-08-03 00:17:33 +03:00
Dmitriy Novozhilov
7c73840e4a [FE 1.0] Introduce new kind of diagnostic factories for deprecation warnings/errors 2021-08-03 00:17:33 +03:00
sebastian.sellmair
ff9643b70e [Gradle] CInteropCommonizerTask: Refine local variable names
^KT-47775
^KT-47053
2021-08-02 20:38:28 +00:00
sebastian.sellmair
153df1dd1a [Gradle] CommonizerIT: Parameterize test on commonizeMultipleCInteropsWithTests
Testing the project w/ and w/o the commonon mistake
of declaring dependsOn edges from test to main source sets

^KT-47775
^KT-47053
2021-08-02 20:38:27 +00:00
sebastian.sellmair
db10732d6c [Gradle] Add integration test project 'commonizeMultipleCInteropsWithTests'
Implemented `test multiple cinterops with test source sets and compilations`

This test will assert source set dependencies
and shared native compilations.

^KT-47775
^KT-47053
2021-08-02 20:38:27 +00:00
sebastian.sellmair
4ae51e1d02 [Gradle] AbstractCInteropCommonizerTask: Ensure outputDirectory path is unique and short enough
^KT-47056 Verification Pending
2021-08-02 20:38:27 +00:00
sebastian.sellmair
02d4c866ca [Gradle] CInterop commonization: Improve grouping and dependency management
^KT-47775 Verification Pending
This implementation will be lenient toward the common
*Test.dependsOn(*Main) mistake.

^KT-47053 Verification Pending
Support source sets that do not have a dedicated
shared native compilation. Also support additional visible source sets
coming from associate compilations.
2021-08-02 20:38:26 +00:00
Ivan Kochurkin
a7e81d5154 Fix test data OverridenSetterVisibility.kt 2021-08-02 20:43:24 +03:00
Igor Yakovlev
bbd21da835 [FIR] Move ARGUMENTS_OF_ANNOTATIONS on top of STATUS phase 2021-08-02 20:29:09 +03:00
Igor Yakovlev
0f3f56f676 [FIR] Update resolve status of annotations to partially resolved 2021-08-02 20:29:08 +03:00
Igor Yakovlev
8fd2ddad12 [FIR] Downgrade ensure resolves to types instead of status 2021-08-02 20:29:07 +03:00
Igor Yakovlev
c0949fbc18 [FIR] Remove redundant ensure to status in FirPackageMemberScope 2021-08-02 20:29:06 +03:00
Igor Yakovlev
9fdd3dc53f [FIR IDE] Add support of lazy phase for annotation arguments 2021-08-02 20:29:06 +03:00
Dmitriy Novozhilov
71def0666e [FIR] Introduce special phase for resolve of enums and class literals 2021-08-02 20:29:05 +03:00
Ivan Kochurkin
afb85026c4 Revert "[FIR] Implement INVISIBLE_SETTER"
This reverts commit b3d7ed56
2021-08-02 20:10:22 +03:00
Ivan Kochurkin
b264a2e5dd [FIR] Fix Consider getter and setter for CANNOT_WEAKEN_ACCESS_PRIVILEGE
Hash: 0e2d765a2d
2021-08-02 20:10:22 +03:00
Dmitriy Novozhilov
17bbedbc50 [Test] Fix FileComparisonFailureFirst comparator to keep sorting stability 2021-08-02 20:07:49 +03:00
Dmitriy Novozhilov
ca40cbede5 [Test] Get rid of BackendKindExtractor 2021-08-02 20:07:49 +03:00
Dmitriy Novozhilov
d43d0071a4 [Test] Add documentation to test infrastructure 2021-08-02 20:07:48 +03:00
Dmitriy Novozhilov
08a1134fff [Test] Remove abstract MultiModuleInfoDumper 2021-08-02 20:07:47 +03:00
Dmitriy Novozhilov
90e06bf403 [Test] Reformat AbstractIrSerializeCompileKotlinAgainstInlineKotlinTest
- Extract IrInlineBodiesHandler to separate file
- Replace SerializeSetter environment configurator with SERIALIZE_IR
    directive
2021-08-02 20:07:46 +03:00
Dmitriy Novozhilov
a66f3d26fd [Test] Replace three fixed phases of tests with step system
Now each test is just a sequence of any number of different steps. There
  are two kinds of steps:
1. Run some facade
2. Run handlers of specific artifact kind

Through the test each module passed to each step (if it is compatible
  by kinds of artifacts)
2021-08-02 20:07:45 +03:00
Dmitriy Novozhilov
ba48f80e53 [Test] Introduce single interface for all entities which provides directive containers and test services 2021-08-02 20:07:44 +03:00
Sergey Shanshin
b42d6a3e85 Fix creating of lazy delegated property in kotlinx.serialization
Fixes Kotlin/kotlinx.serialization#1616
2021-08-02 16:27:03 +00:00
Alexander Shabalin
4c3fb8697b Add FormatToSpan 2021-08-02 16:07:50 +00:00
Igor Chevdar
2c068b8c5a [K/N][IR] Fix for https://youtrack.jetbrains.com/issue/KT-47814 2021-08-02 19:22:08 +05:00
Igor Chevdar
da4113af88 [K/N][runtime] Lazy initialization fix for wasm 2021-08-02 19:20:33 +05:00
Simon Ogorodnik
ed07e1c778 [FIR] Add missing type-alias unwrap in CompletionModeCalculator 2021-08-02 17:07:15 +03:00
Simon Ogorodnik
8e890eba3e [FIR] Hack-in indirectly nested locals resolution 2021-08-02 17:07:15 +03:00
Simon Ogorodnik
7422571c72 [FIR] Fix cycle when loading nested enum within java annotation 2021-08-02 17:07:15 +03:00
sebastian.sellmair
947e97511b [Gradle] CInteropProcess: Prevent compilation when depending on project without c-interops 2021-08-02 12:26:46 +00:00
sebastian.sellmair
4ce3f87361 [Gradle] CommonizerIT: Add failing test when depending on project without c-interops
Adapted existing `test KT-47641 commonizing c-interops does not depend on any source compilation`
to add a project dependency from a project with c-interops (p2)
to a project without any c-interops (p0)

This leads to compilation of project p0, since the
cinteropApiElements configuration was not created on p0
2021-08-02 12:26:45 +00:00
sebastian.sellmair
329991217a [Gradle] Prevent cinterop's from depending on compile tasks
- KotlinNativeCompilation
Change how associate compilations are connected.
Instead of using the implementation configuration, it now uses
the `compileDependencyFiles` directly. This will keep the
implementation configuration from containing any main compilation's
output. Therefore this configuration can still be forwarded to the
cinterop tool.

- KotlinNativeTargetConfigurator.kt CInteropConfigurations.kt
Create special configurations for cinteropApiElements and
cinterop dependencies. This configuration is tries to resolve
only cinterop dependencies when such variants are offered by a project.

^KT-47641 Verification Pending
2021-08-02 12:26:45 +00:00
sebastian.sellmair
7b5a3f8d1b [Gradle] Remove c-interop dependency to main compilation's output 2021-08-02 12:26:45 +00:00
sebastian.sellmair
8e6f84d5cd [Gradle] CommonizerIT: Add test asserting that cinterop commonization does not depend on any source compilation
^KT-47641
2021-08-02 12:26:44 +00:00
Simon Ogorodnik
a353719a6b [FIR] Add dump for fir blocks 2021-08-02 11:24:56 +03:00
Dmitriy Novozhilov
199ec60742 [JVM] Reduce number of param slots for string concatenation
With paramSlot = 200 those tests fails on JDKs which are newer than JDK 9
- testConcatDynamic200Long
- testConcatDynamicIndy200Long()
2021-08-01 22:23:48 +03:00
Dmitriy Novozhilov
5206b45ce3 [Test] Use JDK 11 instead of JDK 9 in modern jdk tests 2021-08-01 22:23:47 +03:00
Dmitriy Novozhilov
fd537e7d5a [Build] Detect JDK 17 in old way using environment variables
There is a problem that toolchains can not detect JDK 17 EAP
  on windows agents. This commit will be reverted after JDK 17 release
  in adoptopenjdk.net
2021-08-01 22:23:47 +03:00
Dmitriy Novozhilov
17fc1da719 [Reflection] Support java records in kotlin reflection
^KT-47760
2021-08-01 22:23:46 +03:00
Dmitriy Novozhilov
8dad8fa813 [Reflection] Support java sealed classes in kotlin reflection
^KT-46778
2021-08-01 22:23:45 +03:00
Dmitriy Novozhilov
fa1d09c778 [FE 1.0] Support java sealed classes
^KT-46778 Fixed
2021-08-01 22:23:45 +03:00
Dmitriy Novozhilov
972211f8e6 [Test] Add directive which allows to attach debugger to instance of JVM in box test 2021-08-01 22:23:44 +03:00
Dmitriy Novozhilov
1fa74ef939 [Test] Move test on modern jdk to separate test runners
This is needed to avoid problems with installation of proper jdk
  on developer machines. Those tests will be moved back to main box
  suites after migrating our tests on LTS versions of jdk (11 and 17
  instead of 9 and 15)
2021-08-01 22:23:43 +03:00
Dmitriy Novozhilov
89bd52c7d2 [Test] Provide path to JDK 9/15/17 via toolchains 2021-08-01 22:23:42 +03:00
Dmitriy Novozhilov
de73622af9 [Test] Mark BB tests on modern jdks with tag and ignore them in different-jdk tests 2021-08-01 22:23:42 +03:00
Dmitriy Novozhilov
c2e2068682 [Test] Add ability to mark group of tests with specific tags
Currently tags can be applied to all tests in specific testdata
  directory by placing `_tags.txt` file in it, where all tags should
  be listed on separate lines. Test generator adds those tags to
  corresponding generated test classes with `@Tag` annotation

Please note that is applicable only to JUnit 5 tests
2021-08-01 22:23:41 +03:00
Dmitriy Novozhilov
b9c549803d [Test] Replace public fun box() with fun box() in all box tests 2021-08-01 22:23:40 +03:00
Dmitriy Novozhilov
c168a561df [Test] Migrate tests for java 15 to regular test infrastructure 2021-08-01 22:23:39 +03:00
Dmitriy Novozhilov
4f73ebbcbd [Test] Migrate tests for java 9 to regular test infrastructure 2021-08-01 22:23:39 +03:00
Dmitriy Novozhilov
ca214bef30 [Test] Add ability to run box test in separate jvm for common codegen tests 2021-08-01 22:23:36 +03:00
Dmitriy Novozhilov
04d9d243de [Test] Convert TestJdkKind.java to Kotlin 2021-08-01 22:23:35 +03:00
Dmitriy Novozhilov
4a09fba3a4 Rename .java to .kt 2021-08-01 22:23:34 +03:00
Dmitriy Novozhilov
e4d2351e03 [Build] Add JDK_17 to list of toolchains 2021-08-01 22:23:34 +03:00
Igor Chevdar
448376f073 [K/N][IR][optmz] Global analysis for top-level initializers
The analysis' goal is to remove redundant calls to initializers
2021-07-31 01:40:00 +05:00
Igor Chevdar
9c6943b8c4 [K/N][IR] Split Devirtualization onto phases
The analysis itself and applying its results to the IR
2021-07-31 01:40:00 +05:00
Igor Chevdar
b11201be81 [K/N][IR][runtime] Implemented lazy per-file initialization strategy 2021-07-31 01:39:59 +05:00
Mark Punzalan
504449f03e FIR: Report UNSAFE_CALL instead of SMARTCAST_IMPOSSIBLE when smartcast
to null.

Currently the error message shows the expression is impossible to
smartcast to the nullable type, which is nonsensical since it's already
that type.
2021-07-30 21:49:50 +03:00
Mark Punzalan
0627dbcb78 FIR IDE: Check stability of smartcast expressions in
KtFirExpressionTypeProvider.getDefiniteNullability().
2021-07-30 21:49:49 +03:00
Mikhail Glukhikh
5283f7b7c6 Make EXPERIMENTAL_API_USAGE_ERR warning till 1.6 for fake override case 2021-07-30 21:21:51 +03:00
Alexander Udalov
3636118743 Introduce typealias JvmRepeatable for j.l.a.Repeatable
#KT-12794 Fixed
2021-07-30 19:53:44 +02:00
Alexander Udalov
847c58d574 Report error on class named Container inside repeatable annotation
#KT-12794
 #KT-47971
2021-07-30 19:53:44 +02:00
Alexander Udalov
5f7803f2db Use double-checked locking in some reflection internals
Note that `volatile` is not needed because in both cases we initialize
an object with a final field, which is subject to safe initialization.
2021-07-30 19:53:33 +02:00
Alexander Udalov
e20b354dbd Check repeatable annotation container parameters, retention, target
#KT-12794
 #KT-47928
2021-07-30 19:53:33 +02:00
Alexander Udalov
0a6d010d1c Support new repeatable annotations in kotlin-reflect
- Unwrap Kotlin-repeatable annotations (with implicit container)
- Introduce `KAnnotatedElement.findAnnotations` to find instances of
  repeated annotations

 #KT-12794
2021-07-30 19:53:33 +02:00
Alexander Udalov
67128c022a Report error if both repeatable annotation and its container are used
#KT-12794
2021-07-30 19:53:32 +02:00
Alexander Udalov
b2550f69bc Report error if repeated annotation is used with JVM target 1.6
#KT-12794
2021-07-30 19:53:32 +02:00
Alexander Udalov
26043f3968 Generate Java @Repeatable on Kotlin-repeatable annotation classes
#KT-12794
2021-07-30 19:53:32 +02:00
Alexander Udalov
92a73d7636 Generate container class for repeatable annotations
#KT-12794
2021-07-30 19:53:32 +02:00
Alexander Udalov
87130edfa2 Support using Java-repeatable annotations in Kotlin
#KT-12794
2021-07-30 19:53:32 +02:00
Alexander Udalov
f723389565 Remove mapping of java.Repeatable to kotlin.Repeatable in JavaAnnotationMapper
The main motivation for this change is that
java.lang.annotation.Repeatable has a parameter for the container
annotation, which is lost during conversion to
kotlin.annotation.Repeatable. To support j.l.a.Repeatable in backend
properly, it's absolutely necessary to be able to load the container
annotation for any repeatable annotation class, so the original
j.l.a.Repeatable needs to be stored in the descriptor and accessible
from the backend.

Instead of mapping j.l.a.Repeatable -> k.a.Repeatable, add a frontend
service PlatformAnnotationFeaturesSupport that will determine if an
annotation is repeatable "according to the platform rules", which for
JVM means that it's annotated with j.l.a.Repeatable.

Some effects of this change include:
- Usages of j.l.a.Repeatable are no longer reported as "deprecated", the
  corresponding test is deleted
- Usages of repeatable annotations declared in Java with non-SOURCE
  retention with LV 1.5 and earlier will now result in a slightly
  different error (REPEATED_ANNOTATION instead of
  NON_SOURCE_REPEATED_ANNOTATION)

 #KT-12794
2021-07-30 19:53:32 +02:00
Dmitry Petrov
ebf837c135 JVM_IR disable IR and bytecode validation by default 2021-07-30 20:21:41 +03:00
Ivan Kochurkin
1a40164ef0 [FIR] Fix resolving of single underscore _
Now compiler throws `UNRESOLVED_REFERENCE` here:

```
val boo = { _: Exception -> `_`.stackTrace }
```
2021-07-30 16:58:07 +00:00
Ivan Kochurkin
8bfaa39a5c [FIR] Implement RESOLVED_TO_UNDERSCORE_NAMED_CATCH_PARAMETER
Split underscore checkers
2021-07-30 16:58:07 +00:00
Ivan Kochurkin
10d9988824 [FIR] Implement DANGEROUS_CHARACTERS 2021-07-30 16:58:06 +00:00
Ivan Kochurkin
83895c49c5 [FIR] Implement INVALID_CHARACTERS 2021-07-30 16:58:06 +00:00
Ivan Kochurkin
63fc3645ab [FIR] Optimize performance and fix UNDERSCORE_IS_RESERVED, simplify code 2021-07-30 16:58:05 +00:00
Ivan Kochurkin
2fbb700ec6 [FIR] Add nonFatalDiagnostics to FirQualifierAccess 2021-07-30 16:58:05 +00:00
Ivan Kochurkin
b307358f69 [FIR] buildErrorExpression for labels with underscored name
Add ConeDiagnosticWithSource, ConeUnderscoreIsReserved, ConeUnderscoreUsageWithoutBackticks diagnostics
2021-07-30 16:58:05 +00:00
Ivan Kochurkin
f5d8535dc5 [FIR] Add aliasSource to FirImport, FirImportImpl 2021-07-30 16:58:04 +00:00
Mikhail Glukhikh
354a06b94a FirSuspendCallChecker: make infix call check more clear 2021-07-30 19:06:55 +03:00
Mikhail Glukhikh
3c2e266c31 FirSuspendCallChecker: use symbol accessor API instead of symbol.fir 2021-07-30 19:06:54 +03:00
Mikhail Glukhikh
e0b1d0db53 FirSuspendCallChecker: drop support of experimental coroutines 2021-07-30 19:06:53 +03:00
Mikhail Glukhikh
807f031dcc FIR: introduce RETURN_FOR_BUILT_IN_SUSPEND diagnostic 2021-07-30 19:06:53 +03:00
Mikhail Glukhikh
229dfd3f5f FIR: introduce builtin suspend related diagnostics 2021-07-30 19:06:51 +03:00
Mikhail Glukhikh
391c4db87c FIR: introduce ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL diagnostics 2021-07-30 19:06:49 +03:00
Mikhail Glukhikh
2397650c24 FIR: introduce NON_LOCAL_SUSPENSION_POINT diagnostic 2021-07-30 19:06:48 +03:00
Mikhail Glukhikh
8f1d07084b FIR: introduce ILLEGAL_SUSPEND_FUNCTION_CALL & PROPERTY_ACCESS diagnostics 2021-07-30 19:06:46 +03:00
Ilya Kirillov
e4992176c1 FIR LC: fix inheritance checking for light classes
Before it was not able to check inheritance with type parameters substitutions like

class A<T>
class B: A<Int>
2021-07-30 18:59:21 +03:00
Ilya Kirillov
767af0dae0 HL API: fix super declarations search for local classes 2021-07-30 18:59:19 +03:00
Ivan Kochurkin
0e2d765a2d [FIR] Consider getter and setter for CANNOT_WEAKEN_ACCESS_PRIVILEGE
Fill source with correct value instead of null
for FirDefaultPropertySetter in light tree converter
2021-07-30 18:07:35 +03:00
Ivan Kochurkin
b3d7ed569d [FIR] Implement INVISIBLE_SETTER 2021-07-30 18:07:34 +03:00
Nikolay Krasko
ca4410aa53 Stop auto-generating expected test data on TeamCity in assertEqualsToFile 2021-07-30 17:46:45 +03:00
Sergey Igushkin
edaf925b19 Reorder Gradle -Xplugin=... so that serialization goes first (KT-47921)
Ensure that the serialization plugin's artifact (and, possibly, some
other prioritized plugin artifacts) are put first to the -Xplugin=...
classpath passed to the compiler.

This fixes the conflict of the serialization plugin with some other
plugins altering the IR in unexpected ways.

Issue #KT-47921
2021-07-30 16:20:14 +04:00
Dmitriy Dolovov
033a9f1589 Bump konanVersion: 1.6.0 2021-07-30 14:52:08 +03:00
Ilya Matveev
e45b13d582 [K/N][New MM] Check if asserts are enabled in thread state asserts 2021-07-30 10:30:50 +00:00
Aleksandr Samofalov
5ee87e126d KMA-51 Use local ObjCExportMapper in ObjCExportTranslatorMobile 2021-07-30 13:13:26 +03:00
Aleksandr Samofalov
d72a399982 KMA-51 Create API to use ObjCExportTranslator to translate functions in IDE 2021-07-30 13:13:26 +03:00
Yahor Berdnikau
90d15f156b Fix toolchain may fail to find tools.jar and false-fail the build.
This may happen when build itself is running on JDK9+ and toolchain
is set to <=JDK1.8. CompilerEnvironment gets 'tools.jar' from the
current Gradle Daemon JDK, but there was a check if exception should be
thrown that uses 'javaVersion' from toolchain provided JDK.

Additionally also fixed 'tools.jar' was not provided for
 'KotlinCompileWithWorkers' task.

^KT-47940 Fixed
2021-07-30 09:59:49 +00:00
Yahor Berdnikau
bab5a4a6c9 Allow to specify JDK for build.
For now it disables debug option.

^KT-47940 In progress
2021-07-30 09:59:49 +00:00
Alexander Gorshenev
9148094bbd Garbage collection capable wrappers for skia interop 2021-07-30 12:54:51 +03:00
Alexander Shabalin
d9483ccb08 Enable stacktraces for RuntimeAssert, TODO 2021-07-30 08:22:32 +00:00
Pavel Kunyavskiy
d18ade088d [K/N] Help message for disabling quarantine flag on dylibs in distribution 2021-07-30 08:17:45 +00:00
Elena Lepilkina
9142b03df5 [K/N][Samples] Use unsigned types in videoplayer 2021-07-30 08:05:44 +00:00
Dmitry Petrov
ca5ebdc13c PSI2IR KT-44855 propagate smart cast information for property values 2021-07-29 21:41:50 +03:00
Mikhael Bogdanov
cdbd0eb932 Reopen KT-47920 test and add missed .txt files
#KT-47920 Open
2021-07-29 19:52:59 +02:00
Mikhael Bogdanov
824d6ab5cc Update tests affected by 'ProhibitSimplificationOfNonTrivialConstBooleanExpressions' feature 2021-07-29 19:45:57 +02:00
Mikhael Bogdanov
1e2547d0d0 Temporary mute test-lombok-with-kapt test
#KT-47945
2021-07-29 19:45:57 +02:00
Mikhael Bogdanov
588952bc9a Fix maven tests 2021-07-29 19:45:57 +02:00
Mikhael Bogdanov
a1bd728aef Update SNAPSHOT version in maven projects/tests 2021-07-29 19:45:57 +02:00
Mikhail Glukhikh
55f7bb2756 Fix FIR PSI consistency test (definitely not-null types) 2021-07-29 19:45:57 +02:00
Alexander Udalov
d36c56497e Minor, improve CLI test internalArgOverrideOffLanguageFeature
Avoid disabling language features which cannot be disabled anymore.
2021-07-29 19:45:57 +02:00
Dmitriy Novozhilov
262c9e88d1 [FE 1.0] Fix remaining codegen spec tests 2021-07-29 19:45:57 +02:00
Denis.Zharkov
ee68962c02 Ignore Jvm8RuntimeDescriptorLoaderTestGenerated::testMapRemove
For now, JavaResolverSettings in runtime are different from
default language version, so it might have a little bit different API surface

In future, it's worth considering changing JavaResolverSettings.Default
once default language version is changing

  #KT-47903
2021-07-29 19:45:57 +02:00
Mikhael Bogdanov
4fe846fb81 Fix test affected by InstantiationOfAnnotationClasses feature 2021-07-29 19:45:57 +02:00
Mikhael Bogdanov
1347ee8c7d Update DiagnosicTestGenerated affected by 'PrivateInFileEffectiveVisibility' feature 2021-07-29 19:45:57 +02:00
Denis.Zharkov
d2ad421e0b Fix test data for definitelyNotNullType 2021-07-29 19:45:57 +02:00
Denis.Zharkov
8f484fcf88 Fix propagation of definitelyNotNull types from overrides 2021-07-29 19:45:57 +02:00
Victor Petukhov
cba224b7b8 Update spec black box tests 2021-07-29 19:45:56 +02:00
Mikhael Bogdanov
baaa615e09 Update FirOldFrontendDiagnosticsTestGenerated tests 2021-07-29 19:45:56 +02:00
Mikhael Bogdanov
70e4472c99 Update Fir2IrTextTestGenerated tests 2021-07-29 19:45:56 +02:00
Victor Petukhov
d2a7434cff Update testdata 2021-07-29 19:45:56 +02:00
Denis.Zharkov
f34726ff91 Fix test data for ForeignAnnotations 2021-07-29 19:45:56 +02:00
Dmitriy Novozhilov
2ae546576c [FE 1.0] Update DUPLICATE_LABEL_IN_WHEN testdata
New diagnostics started to report because in 1.6 we assume that
  `1` is typed const of type Int instead of literal const
2021-07-29 19:45:56 +02:00
Dmitriy Novozhilov
b1d17cfd7b [FE 1.0] Force resolve annotations on type arguments
^KT-46173
2021-07-29 19:45:56 +02:00
Dmitriy Novozhilov
e316cd04b6 [FIR] Fix consistency of FE 1.0 and FIR test data 2021-07-29 19:45:56 +02:00
Denis.Zharkov
699d53e7f9 Fix ISE when copying a function with @NotNull bounded type parameters
For example in the case:
<_A extends @NotNull B, B> void f4(_A x, B y) { }

ISE had happened because while substituting the function
we've been creating copies of old type parameters and when initializing
bounds for one of them bounds for other may not be initialized yet
at the same time bounds were necessary for makesSenseToBeDefinitelyNotNull
2021-07-29 19:45:56 +02:00
Mikhael Bogdanov
0c419eac1a Update Java8BuiltInsWithJDKMembersTest tests 2021-07-29 19:45:56 +02:00
Mikhael Bogdanov
0f216f4d37 Update LoadJava8TestGenerated tests 2021-07-29 19:45:56 +02:00
Mikhael Bogdanov
a544d6948b Fix simpleUnaryOperators.kt test 2021-07-29 19:45:56 +02:00
Victor Petukhov
f84adcb378 [FE 1.0] Fix some foreign annotation tests 2021-07-29 19:45:56 +02:00
Victor Petukhov
ca0b8be53b [FE 1.0] Fix some diagnostic spec tests 2021-07-29 19:45:55 +02:00
Alexander Udalov
0ed9b75428 Minor, fix diagnostic test data for FIR 2021-07-29 19:45:55 +02:00
Alexander Udalov
b442e598d3 Fix test data of codegen tests for KT-47328 for 1.6 2021-07-29 19:45:55 +02:00
Alexander Udalov
f1ac5796ed Fix test data of compileJavaAgainstKotlin for 1.6
See LanguageFeature.DefinitelyNotNullTypeParameters.
2021-07-29 19:45:55 +02:00
Alexander Udalov
2d0d83a54b Fix AntTaskTestGenerated.testLanguageVersion for 1.6 2021-07-29 19:45:55 +02:00
Alexander Udalov
6af042c1dd Temporarily disable runtime version consistency checks
To be enabled after the project is fully bootstrapped and default
language version is advanced to 1.6.
2021-07-29 19:45:55 +02:00
Victor Petukhov
95492f7370 [FE 1.0] Fix some diagnostic tests 2021-07-29 19:45:55 +02:00
Dmitriy Novozhilov
7250aed3b5 [FE 1.0] Fix some diagnostic tests 2021-07-29 19:45:55 +02:00
Mikhael Bogdanov
c9c82ab3a6 Update test affected by SafeCallsAreAlwaysNullable feature 2021-07-29 19:45:55 +02:00
Mikhael Bogdanov
c8094f7439 Add readable toString for JavaTypeEnhancementState 2021-07-29 19:45:55 +02:00
Mikhael Bogdanov
f590c3201a Update ScriptingHostTest.testCompileOptionsLanguageVersion test 2021-07-29 19:45:55 +02:00
Mikhael Bogdanov
70fe984738 Update classTypeParameter.kt test 2021-07-29 19:45:55 +02:00
Mikhael Bogdanov
cc5ba4c0af Update diagnostic tests 2021-07-29 19:45:54 +02:00
Mikhael Bogdanov
0cccb76652 Update tests affected by ProperTypeInferenceConstraintsProcessing feature 2021-07-29 19:45:54 +02:00
Mikhael Bogdanov
235359e028 Ignore tests cause of KT-47542
#KT-47542
2021-07-29 19:45:54 +02:00
Mikhael Bogdanov
390eda1b9d Fix CompileKotlinAgainstCustomBinariesTest tests 2021-07-29 19:45:54 +02:00
Mikhael Bogdanov
7854e9c3d7 Update CLI tests 2021-07-29 19:45:54 +02:00
Mikhael Bogdanov
1187e786f4 Fix compilation in MappedExtensionProvider.kt 2021-07-29 19:45:54 +02:00
Mikhael Bogdanov
5f3f2e762a Update JS tests 2021-07-29 19:45:54 +02:00
Mikhael Bogdanov
1fe1c197ee Mute WASM safeAccess.kt test
Update JS tests
2021-07-29 19:45:54 +02:00
Mikhael Bogdanov
29f6ec4f40 Update defaultSnapshotVersion to 1.6.255-SNAPSHOT 2021-07-29 19:45:54 +02:00
Mikhael Bogdanov
38fb5e16ef Update test affected by ApproximateIntegerLiteralTypesInReceiverPosition feature 2021-07-29 19:45:54 +02:00
Mikhael Bogdanov
805778e782 Fix compilation cause of KT-47797 problem
#KT-47797
2021-07-29 19:45:54 +02:00
Mikhael Bogdanov
7cbd6908f9 Update test affected by ProhibitUsingNullableTypeParameterAgainstNotNullAnnotated feature 2021-07-29 19:45:53 +02:00
Mikhael Bogdanov
228100ef09 Upgrade toolchain to api/lv 1.4 2021-07-29 19:45:53 +02:00
Mikhael Bogdanov
a919aab3ab Update metadata related logic after switch to 1.6 2021-07-29 19:45:53 +02:00
Mikhael Bogdanov
ee07ff7982 Switch latest stable version to 1.6 2021-07-29 19:45:53 +02:00
Dmitry Petrov
caa13b33b1 JVM_IR minor: update testdata 2021-07-29 20:45:16 +03:00
Dmitry Petrov
b93dff003f JVM_IR configure loop shape in the backend context 2021-07-29 20:45:15 +03:00
Dmitry Petrov
38d6c8ded0 JVM_IR generate range loops as counter loops when possible 2021-07-29 20:45:14 +03:00
Sergey Igushkin
d0f207071c Prepare for enabling HMPP by default and migrating the flags (KT-40245)
* Add a new single flag for enabling HMPP:
  kotlin.mpp.hierarchicalStructureSupport

  When this flag is enabled:

  * The old HMPP flags gets enabled, too, for old consumers
  * The commonizer gets enabled as well
  * An internal flag is set to indicate that the old flags were set by
    the plugin

* Add an internal flag that we should flip when HMPP becomes the
  default: kotlin.internal.mpp.hierarchicalStructureByDefault

  With this flag is enabled:

  * All MPP projects will use the composite artifact and
    compile metadata with the KLIB compiler
  * The compatibility metadata artifact will be gone
  * The new HMPP flag is enabled by default

* Add consistency checks for new VS old flags

Issue #KT-40245
2021-07-29 19:12:53 +03:00
Pavel Kirpichenkov
352c624601 Provide built-ins module name in IrLinker for debugger 2021-07-29 19:04:25 +03:00
Dmitriy Novozhilov
046730c62c [Test] Integrate AbstractCompileTimeConstantEvaluatorTest to AbstractDiagnosticTest
^KT-47898
2021-07-29 15:25:53 +03:00
pyos
c401582770 FE: do not wrap types with enhancements if they're the same 2021-07-29 14:52:51 +03:00
pyos
8c524c2f89 FE: do not attach enhancements to parts of enhanced flexible types 2021-07-29 14:52:51 +03:00
pyos
6cb6abee98 FE: do not create multiple layers of enhancements for warnings 2021-07-29 14:52:51 +03:00
Victor Petukhov
5684b6977a Do preparation of enhancement as well (for types with enhancement), during subtype checks
^KT-47899 Fixed
2021-07-29 14:23:56 +03:00
Victor Petukhov
c5d783596d Check type parameter bounds by java nullability annotations not only in basic resolution context
^KT-47920 Fixed
2021-07-29 14:23:55 +03:00
Victor Petukhov
20d50cfee7 Prevent leaking of type parameter erasion results cache into static scope 2021-07-29 14:23:55 +03:00
Victor Petukhov
6706ee87ad Introduce TypeParameterUpperBoundEraser to memorize results of type parameters erasion computation
^KT-47785 Fixed
2021-07-29 14:23:54 +03:00
Victor Petukhov
f9cb0d61a8 Don't apply Java defaulting nullability annotations rules to unbounded wildcards
^KT-47396 Fixed
2021-07-29 14:23:53 +03:00
Victor Petukhov
99491014e4 Prefer flexible nullability by Java annotations to nullable one if the corresponding type parameter has nullable bound
^KT-47422 Fixed
2021-07-29 14:23:52 +03:00
Dmitriy Novozhilov
2c9857b880 Assume LV 1.6 ready for preview
^KTIJ-19253 Fixed
2021-07-29 13:28:15 +03:00
Dmitriy Dolovov
59dcef81f7 [K/N][Gradle] Make sure K/N Gradle plugin don't fail when K/N distribution directory has no platform libs 2021-07-29 12:56:55 +03:00
Dmitriy Dolovov
66c9d658e4 [K/N] Keep the Kotlin/Native compiler version inside of the K/N distribution
Restore the behavior that was accidentally disabled.
2021-07-29 12:56:50 +03:00
Dmitriy Dolovov
b505486063 K/N, Minor: Drop unused exception class: KonanIrDeserializationException 2021-07-29 12:56:45 +03:00
Dmitriy Dolovov
50d150ace5 K/N: Avoid reporting excessive "error: compilation failed: null" message
This could happen if the source of the exception is inside of KotlinIrLinker/KonanIrLinker or IR deserializers.
2021-07-29 12:56:40 +03:00
Ilya Matveev
3e823d62a9 [K/N][kotlin.test] Make GeneratedSuites public
Issue #KT-47915 fixed
2021-07-29 08:44:32 +00:00
Ivan Kochurkin
d4e1cded59 [FIR] Implement RESOLUTION_TO_CLASSIFIER 2021-07-28 23:18:38 +03:00
Ivan Kochurkin
2574dc907c [FIR] Implement FUNCTION_EXPECTED 2021-07-28 23:17:31 +03:00
Ivan Kochurkin
263e40e753 [FIR] Implement NO_RECEIVER_ALLOWED 2021-07-28 22:52:06 +03:00
Dmitry Savvinov
45a384bb77 Exclude stdlib-common from non-JVM targets as well
This is a continuation of KT-46936. This commit removes stdlib-common
from platform-specific source sets of JS/Native targets, as well as
Android and 'jvm { withJava() }'

The tests are made on kotlin-ide side, see the KT-46936 for attached
commits.

^KT-46936
^KT-47695 Fixed
^KT-47604 Fixed
2021-07-28 20:02:13 +03:00
Dmitry Petrov
ce79fc77c9 JVM minor cleanup in bytecode analyzers 2021-07-28 19:53:39 +03:00
Hung Nguyen
f95c50064c KT-45777: Refactor IncrementalJvmCache to support classpath snapshotting
Extract minimal required information into the new `KotlinClassInfo`
class. This info will be part of the classpath snapshot of the
`KotlinCompile` task in an upcoming change.

Bug: KT-45777
Test: Existing tests should pass (this is a refactoring-only change)
2021-07-28 19:32:10 +03:00
Pavel Kirpichenkov
19467861c9 [MPP] Fix false positive expect-actual mismatch
Use type refiner to correctly expand actual type alias - expect
class chains, produced by the commonizer. In a case when type
refiner doesn't exist for module create a one-shot thread local
instance. This might happen with modules without source code
in project (coming from build system model).

^KT-46691 Fixed
2021-07-28 18:57:08 +03:00
Pavel Kirpichenkov
2d91917ac7 [MPP] Make type refinement capability aware of HMPP state
Introduce intermediate state for cases when module doens't
have a type refiner even though HMPP is enabled.

KT-46691
2021-07-28 18:57:07 +03:00
Pavel Kirpichenkov
566640aa6d [MPP] Move KotlinTypeRefinerImpl (frontend -> descriptors)
ExpectedActualResolver in certain cases needs an ability
to create a standalone refiner instance, see the following
commits. A direct module dependency (resolution -> frontend)
can't be added, the opposite one already exists which leads
to a dependency cycle. Both modules depend on core.descriptors
module where KotlinTypeRefiner resides.

KT-46691
2021-07-28 18:57:07 +03:00
Pavel Kirpichenkov
1f3004a667 [MPP] Support multiple levels of actual type alias expansions
Commonizer might transform typealias chains into several
expect classes with actual type aliases. In this case
refining a common type once is not enough as the result
will be another expect type from type alias expansion.

KT-46691
2021-07-28 18:57:05 +03:00
Andrey Zinovyev
d84cc4333c [FIR] Add INITIALIZATION_BEFORE_DECLARATION diagnostic 2021-07-28 16:56:54 +03:00
Andrey Zinovyev
b706e776ad [FIR] Add VARIABLE_WITH_NO_TYPE_NO_INITIALIZER diagnostic 2021-07-28 16:56:53 +03:00
Svyatoslav Scherbina
a63f218dd3 Stop using ModuleDescriptor.name for top-level ObjCExport name prefix
^KT-47809 Fixed

Do similar for C export.
2021-07-28 12:46:11 +00:00
Alexander Shabalin
48a2b23b3a Add a separate compiler switch for runtime asserts 2021-07-28 07:43:08 +00:00
Alexander Likhachev
c3515cc338 [Gradle] Use compiler argument -opt-in instead of '-Xopt-in'
#KT-35832 Fixed
2021-07-28 05:58:58 +00:00
Alexander Likhachev
10f9c217fd [Gradle] Advance K/N version to 1.6.0-dev-1728 2021-07-28 05:58:58 +00:00
Dmitry Petrov
4267852030 JVM cleanup bytecode analyzers 2021-07-28 08:04:55 +03:00
pyos
e9b177352c JVM_IR: do not inline reads of constructor arguments into accessors 2021-07-28 02:16:01 +02:00
Vasily Levchenko
2baf344f5f [kotlin gradle plugin] enable to work with embedded k/n compiler. 2021-07-27 19:44:31 +00:00
Vasily Levchenko
1eb951749d [build][kotlin-native] native compiler embeddable 2021-07-27 19:44:31 +00:00
Viacheslav Kormushkin
fa2e787f76 CocoaPods Gradle plugin: Support incremental task execution when switching between Xcode and terminal
#KT-37511
2021-07-27 16:08:32 +00:00
Ilya Kirillov
91ecaa32e3 HL API: render local fqNames in reference resolve tests 2021-07-27 17:58:47 +03:00
Ilya Kirillov
77fcb12af8 Fix project leaking in tests
The project was leaking via MockApplication -> LowMemoryWatcherManager -> List<Project>
It happened due to unregistered disposable provided to the MockApplication
2021-07-27 17:58:47 +03:00
Ilya Kirillov
f19dfd9d2a HL API: restore SymbolByReferenceTest
Now it is possible as references are working in HL API tests now
2021-07-27 17:58:46 +03:00
Ilya Kirillov
c678d4b506 HL API: generate reference resolve tests
The testdata is taken from corresponding IDE reference resolve tests
2021-07-27 17:58:45 +03:00
Ilya Kirillov
7ba8e7d1d3 LL API: fix KtPackageProvider package existent checks for tests
Before it was not able to check nested packages for existence

Also, implement unimplemented getKotlinSubPackageFqNames
2021-07-27 17:58:45 +03:00
Ilya Kirillov
4fe240d1b4 HL API: fix KtUserType kt -> fir mapping for non-IDEA usages
createType(KtTypeElement) requires some access to IJ services which are unavailable to IJ core
2021-07-27 17:58:44 +03:00
Ilya Kirillov
970d7b5a78 HL API: implement tests for reference resolve 2021-07-27 17:58:43 +03:00
Ilya Kirillov
55489b6249 FIR IDE: fix containing KtFirSymbolContainingDeclarationProvider for implicit constructors 2021-07-27 17:58:42 +03:00
Ilya Kirillov
eb69153fbc HL API: fix renderer for package symbols 2021-07-27 17:58:40 +03:00
Mikhail Glukhikh
84bd347841 Make EXPERIMENTAL_API_USAGE_ERR warning till 1.6 for signature type case 2021-07-27 14:58:56 +03:00
Mikhail Glukhikh
810def829c Make EXPERIMENTAL_ANNOTATION_ON_OVERRIDE warning till 1.6 2021-07-27 14:58:55 +03:00
Mikhail Glukhikh
bb38eaae61 Postpone OptIn release to version 1.7 2021-07-27 14:56:54 +03:00
Alexander Udalov
0a9498f7e2 Build: suppress deprecated JVM target warning globally
There seems to be no point in configuring the compiler argument per
project. This argument will be deleted soon anyway, when we remove
support for JDK 1.6 & 1.7.

Also remove `disableDeprecatedJvmTargetWarning`. It didn't have any
effect in all modules where it was applied because these modules
reassign `freeCompilerArgs` anyway, with
`-Xsuppress-deprecated-jvm-target-warning` in it.
2021-07-27 13:35:39 +02:00
Alexander Udalov
91c39ed01c Build: remove obsolete compiler arguments
These compiler arguments enable features which are enabled by default in
the current Kotlin anyway.

The only exception is in :compiler:cli which uses an old language
version.
2021-07-27 13:35:38 +02:00
Steffi Stumpos
707e1c7f8d [Test] Add service to provide additional classpath to box tests 2021-07-27 14:05:51 +03:00
Yahor Berdnikau
a55eacd8db Migrate Gradle daemon memory leak tests to JUnit5.
^KT-45745 In Progress
2021-07-27 11:43:32 +03:00
Pavel Kunyavskiy
be0a0a7784 [K/N] Support escape analysis with new mm 2021-07-27 08:22:02 +00:00
Igor Yakovlev
f671061328 [FIR IDE] Add check resolved type for phase less than Types 2021-07-26 23:08:54 +02:00
Igor Yakovlev
02f2f6c148 [FIR IDE] Code review minor changes 2021-07-26 23:08:54 +02:00
Igor Yakovlev
4eb534e39b [FIR IDE] Remove withFirWithPossibleResolve inside function 2021-07-26 23:08:54 +02:00
Igor Yakovlev
563f8c8541 [FIR IDE] Split names of withRef function to phase and type versions 2021-07-26 23:08:54 +02:00
Igor Yakovlev
66fa624ab7 [FIR IDE] Fix IDE return type calculators 2021-07-26 23:08:54 +02:00
Igor Yakovlev
4711577b17 [FIR IDE] Add containing file workaround for FirLightAnonymousClassForSymbol 2021-07-26 23:08:54 +02:00
Igor Yakovlev
a4426cd40d [FIR IDE] Fix invalid partial resolve of file annotations 2021-07-26 23:08:54 +02:00
Igor Yakovlev
e1c8f302a4 [FIR IDE] Make fir resolve phase volatile and remove locks 2021-07-26 23:08:54 +02:00
Igor Yakovlev
78e249c2d5 [FIR IDE] Fix creating fir light classes for NotUnderContentRootModuleInfo module content 2021-07-26 23:08:53 +02:00
Igor Yakovlev
ab2aaec4fe [FIR IDE] Ensure resolve for status transformer 2021-07-26 23:08:53 +02:00
Igor Yakovlev
4e870b6796 [FIR IDE] Fix invalid resolve for fir synthetic properties and accessors 2021-07-26 23:08:53 +02:00
Igor Yakovlev
6700179ee4 [FIR IDE] Add LibraryModuleSourceInfoBase and filter out light classes for sources from libraries 2021-07-26 23:08:53 +02:00
Igor Yakovlev
a0418c3146 [STUBS] Fix invalid classId calculation for KtObjectLiteralExpression 2021-07-26 23:08:53 +02:00
Igor Yakovlev
6869fbbfe5 [FIR IDE] Insert ensure resolve into checkers and scopes 2021-07-26 23:08:53 +02:00
Igor Yakovlev
2fd6c55fc8 [FIR IDE] Replace FIR phase update to FIR IDE 2021-07-26 23:08:53 +02:00
Ilya Chernikov
df9a3c0300 Restore scripting-ide-services testing, fix coroutines dependency 2021-07-26 21:16:50 +03:00
Ivan Kochurkin
173813f7cf [FIR] Implement REIFIED_TYPE_FORBIDDEN_SUBSTITUTION 2021-07-26 21:13:25 +03:00
Ivan Kochurkin
bade6cb611 [FIR] Improve TYPE_PARAMETER_AS_REIFIED detecting, implement TYPE_PARAMETER_AS_REIFIED_ARRAY, TYPE_PARAMETER_AS_REIFIED_ARRAY_WARNING 2021-07-26 21:13:25 +03:00
Ivan Kochurkin
2333b1bcf6 [FIR] Implement BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY 2021-07-26 21:13:23 +03:00
Alexander Udalov
cbdd0f579a Regenerate Gradle options 2021-07-26 19:36:53 +02:00
Alexander Udalov
0083ef053b Remove Gradle option annotation for -Xbuiltins-from-sources
This is an internal compiler argument for FIR which doesn't seem
valuable enough to be exposed in Gradle, because it'd require to perform
some kind of deprecation if it's changed or removed. It'll still be
possible to use it via `freeCompilerArgs += "-Xbuiltins-from-sources"`.

Note that generated Gradle options are not changed because the generator
was not rerun after adding this compiler argument. (And the test that
checks that the generator was run is failing right now.)
2021-07-26 19:36:53 +02:00
Alexander Udalov
fe18e3fa31 Do not use uninterruptible file channels in FileChannelUtil
To avoid illegal access errors from incremental compilation on JDK 16+.

 #KT-45689 Fixed
 #KT-47152 Fixed
2021-07-26 19:27:09 +02:00
Alexander Udalov
2ca241c82c Copy FileChannelUtil from intellij-core
#KT-45689
 #KT-47152
2021-07-26 19:27:09 +02:00
Alexander Udalov
698c0bb2a9 Replace --illegal-access workaround with --add-exports
--illegal-access=permit doesn't work since JDK 17.

 #KT-47152 Fixed
2021-07-26 19:27:09 +02:00
Nikolay Lunyak
a44048e713 Add withBindThis to field configuration 2021-07-26 16:12:16 +00:00
Aleksei.Cherepanov
4003cd2832 Fix backward compatibility of portable caches for 212 idea
Write zero to deletedCount value of counters map instead of removing it in context of LookupStorage performance improving
2021-07-26 18:58:12 +03:00
Alexander Shabalin
a24eab9745 Fix STMS tests 2021-07-26 15:09:59 +00:00
Alexander Udalov
5526281c54 Minor, refactor diagnostic tests on repeatable annotations 2021-07-26 14:33:32 +02:00
Alexander Udalov
56866e6927 JVM IR: move java.lang.annotation symbols to JvmSymbols.javaAnnotations
Since a separate instance of AdditionalClassAnnotationLowering is
created for each source file, symbols for these classes were created as
many times as there were source files in the module.

Also inline some variables in the process and move around some methods.
2021-07-26 14:33:32 +02:00
Alexander Udalov
50f7594d9e Minor, move RepeatableAnnotationChecker to separate file 2021-07-26 14:33:31 +02:00
Alexander Udalov
104188c035 Render annotation arguments in bytecodeListing tests 2021-07-26 14:33:30 +02:00
Yahor Berdnikau
7958307d28 Allow to override build options for particular builds.
^KT-45745 In Progress
2021-07-26 14:27:47 +02:00
Yahor Berdnikau
25192cd639 Fix project options are ignored for builds.
Fix 'forceOutput' and 'enableGradleDebug' project level options are not
taken into account when running particular build.

^KT-45745 In Progress
2021-07-26 14:27:47 +02:00
Yahor Berdnikau
a49b36f6b1 Add additional output assertions.
- check if output contains string exactly times
- check if output does not contain Kotlin warnings
- check expected incremental compilation

^KT-45745 In Progress
2021-07-26 14:27:47 +02:00
Yahor Berdnikau
c816d6f2e5 Modify file exists assertion.
Additionally allow to check if file exists in any location, even outside
of the project.

^KT-45745 In Progress
2021-07-26 14:27:47 +02:00
Yahor Berdnikau
18d74e62a6 Add additional shortcuts for common project files.
^KT-45745 In Progress
2021-07-26 14:27:47 +02:00
Yahor Berdnikau
35677f4727 Add random hash to the tempDir project dir.
This will allow to create several similar projects from one resource
project in a single test.

^KT-45745 In Progress
2021-07-26 14:27:46 +02:00
Andrey Zinovyev
8a0941a85a [FIR] Report deprecations in qualified expressions 2021-07-26 14:50:54 +03:00
Mikhail Glukhikh
98bd6f5d3e Fix "implicit type" exception in FIR OptIn checker 2021-07-26 10:13:13 +03:00
Mikhail Glukhikh
2a6355b64c FIR: use coneType instead of coneTypeSafe in OptIn checkers 2021-07-23 23:59:01 +03:00
Mikhail Glukhikh
73539cf342 FIR: use symbols as base for OptIn-checkers 2021-07-23 23:59:00 +03:00
Mikhail Glukhikh
cb847b945d FIR: use getAnnotationByClassId instead of getAnnotationByFqName 2021-07-23 23:58:59 +03:00
Mikhail Glukhikh
7cbea12c8a FIR: store all annotationContainers in checker context 2021-07-23 23:58:58 +03:00
Mikhail Glukhikh
d020948933 FIR: support EXPERIMENTAL_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION... 2021-07-23 23:58:57 +03:00
Mikhail Glukhikh
543ce06d85 FIR OptIn: temporarily replace error USAGE with warning
This commit is required for FP test to pass,
because FP test does not see module -Xopt-in=... flags.
2021-07-23 23:58:56 +03:00
Mikhail Glukhikh
82f268d611 FIR: add EXPERIMENTAL_API_USAGE reporting 2021-07-23 23:58:55 +03:00
Mikhail Glukhikh
3235b09a92 FIR: introduce MutableCheckerContext to save performance 2021-07-23 23:48:19 +03:00
Denis.Zharkov
b547870d71 Use unsigned version of short numbers in ZipImplementation
Because some two-byte represented numbers (like amount of files in the zip)
exceed 32767 (but less than 65534)
2021-07-23 21:38:46 +03:00
Denis.Zharkov
ea5157cadc Change type of KotlinCoreEnvironment::projectEnvironment type 2021-07-23 21:38:45 +03:00
Denis.Zharkov
d6adac8dd0 Move FastJarFileSystem to ProjectEnvironment and link to the root disposable 2021-07-23 21:38:45 +03:00
Denis.Zharkov
3afed7f972 Fallback to CoreJarFileSystem when JDK doesn't support buffers unmapping 2021-07-23 21:38:43 +03:00
Denis.Zharkov
c6525974d0 Move handlers cache from static field to the instance of FastJarFileSystem 2021-07-23 21:38:43 +03:00
Denis.Zharkov
03e5dc6117 Force unmapping MappedByteBuffer
Otherwise, on Windows daemon might hold mapped regions for some time
(until those objects are collection) and during the time those file become
locked (it's impossible to modify or remove them)

Reflection/Unsafe of course is not a cool thing to use, but JDK still
(already for 18 years) doesn't have public API for this

See https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4724038
And https://stackoverflow.com/questions/2972986/how-to-unmap-a-file-from-memory-mapped-using-filechannel-in-java
2021-07-23 21:38:42 +03:00
Denis.Zharkov
4e11c670c6 Clear cleanFileAccessorsCache for FastJarFileSystem 2021-07-23 21:38:41 +03:00
Denis.Zharkov
7ca2a83f08 Use native endian mode from MappedByteBuffer 2021-07-23 21:38:40 +03:00
Denis.Zharkov
33cf058b55 Use MappedBuffer for FastJarFileSystem implementation 2021-07-23 21:38:40 +03:00
Denis.Zharkov
8f06e59d3b Implement new faster version of Jar virtual file system
It's only enabled by default in FIR and might be turned on with a CLI flag

The main idea is that default FarFS re-read ZIP file list each time when
class file is requested that is quite slow.
We read it once and them reading bytes from the known offset.

Also, unlike the default version we don't perform attributes check on each access
On the one hand, it works faster on the other it might not notice that one
of the JAR has been changed during compilation process
But looks like it's not supposed to be a frequent even during
compilation of a single module
2021-07-23 21:38:38 +03:00
Dmitriy Novozhilov
559e7d223a [FIR] Add friends path from Module in CLI compiler 2021-07-23 17:28:42 +03:00
Dmitriy Novozhilov
d9d2a9cc31 Move BuildSessionLoggerTest to :kotlin-gradle-plugin tests
There was a problem that :kotlin-gradle-statistics:test can not be
  properly imported and kotlin stdlib wasn't accessible in it. I didn't
  find a way to fix it in :kotlin-gradle-statistics module, so I just
  moved tests from it to others gradle plugin tests
2021-07-23 17:15:55 +03:00
Anton Bannykh
a7549be95e JS IR IC: report cache validataion duration when up-to-date 2021-07-23 17:10:07 +03:00
Anton Bannykh
4cee44cd6e JS IR IC: add a flag for DCE hack
The deserialized PIR does not support declaration mutation.
Until that's fixed the associatedObject removal optimization
has to be disabled.
2021-07-23 17:10:07 +03:00
Anton Bannykh
508d3bd9c0 JS IR IC: IC data may reference additional original declarations
Function types, which are created on the fly from lowerings are one such example.
2021-07-23 17:10:06 +03:00
Anton Bannykh
fa21132704 JS IR IC: fix order storage
Some classes don't survive till the end. Their declaration lists
need to be stored nevertheless.
2021-07-23 17:10:06 +03:00
Anton Bannykh
c6ab195a87 JS IR IC: invalid loops references exist after lowerings 2021-07-23 17:10:04 +03:00
Anton Bannykh
0130d18ea9 JS IR IC: deserialization fix 2021-07-23 17:10:03 +03:00
Anton Bannykh
058ca16af7 JC IR IC: correct signatures for function types created during lowerings 2021-07-23 17:10:02 +03:00
Anton Bannykh
8553c6ef58 JS IR IC: pass through more compiler flags 2021-07-23 17:10:02 +03:00
Yahor Berdnikau
5dc6e1b473 Fix no duplicate strategy was set for compilation with 'withJava()'.
In such case Kotlin jvm compilation has additionally java resource dir
that points to the same location. So ProcessResources task copies same
file twice. Fixed by setting ignore duplicates strategy.

^KT-46978 Fixed
2021-07-23 14:03:57 +00:00
Nikolay Krasko
83023c2073 Remove 202 platform support in build scripts 2021-07-23 16:58:28 +03:00
Nikolay Krasko
ec99585eb9 Remove explicit registration of classFileDecompiler EP and core.xml 2021-07-23 16:58:27 +03:00
Nikolay Krasko
1b3046a61b Cleanup 202 bunch files
Leave 202 in .bunch file to give some time for updating build server
2021-07-23 16:58:26 +03:00
Nikolay Krasko
000a437315 Update .bunch file after 202 -> 203 switch 2021-07-23 16:58:25 +03:00
Nikolay Krasko
bba0dfb469 Cleanup as42 bunch files
We don't build AS42 plugin from main kotlin repo anymore.
2021-07-23 16:58:24 +03:00
Dmitry Petrov
34f5b85ae5 IR KT-47840 fix-point solution for closure conversion 2021-07-23 14:58:23 +03:00
Jinseong Jeon
e9f2d574d5 FIR IDE: simplify HL APIs for PsiType
The idea is to convert `KtType` to `PsiType`, along with the given
`PsiElement` context, instead of providing individual API to convert
different psi source to `PsiType`. To that end, we need to
migrate/rewrite some APIs/implementations that retrieve `KtType` from
different source of `PsiElement`.
2021-07-23 13:28:14 +02:00
Jinseong Jeon
f02f3c76ae FIR IDE: API to resolve KtTypeReference to KtType 2021-07-23 13:28:11 +02:00
Jinseong Jeon
5358d4f07c FIR IDE: construct function type from a function as PsiType 2021-07-23 13:28:05 +02:00
Jinseong Jeon
f19a501cc7 FIR IDE: common super type of given KtExpression's 2021-07-23 13:27:59 +02:00
Jinseong Jeon
5690b4d8c2 FIR IDE: get the return type of KtDeclaration as PsiType 2021-07-23 13:27:57 +02:00
Konstantin Tskhovrebov
de4c2d35ab Assemble fat framework if Xcode requires several architectures.
#KT-47653
2021-07-23 11:00:35 +00:00
Konstantin Tskhovrebov
68a3c5f378 Use 'ARCHS' Xcode env for assembleAppleFramework task registration.
#KT-47653
2021-07-23 11:00:34 +00:00
Konstantin Tskhovrebov
414e735a67 Move native target definition by sdk and arch from Cocoapods to MPP plugin.
#KT-47653
2021-07-23 11:00:34 +00:00
Dmitriy Novozhilov
9b00776dba [FIR] Create CFG node for ::class calls 2021-07-23 12:20:39 +03:00
Yahor Berdnikau
c5ce52eef5 Configure Android SDK in new test dsl. 2021-07-23 08:11:03 +00:00
Yahor Berdnikau
1e758c6767 Toolchain takes into account kotlin options set via Android extension.
This extension updates not common task kotlin options, but special
field in the task. Toolchain will also check this field to decide
whether it should set 'jvmTarget' or not.

^KT-47754 Fixed
2021-07-23 08:11:02 +00:00
Yahor Berdnikau
e3b219b68f Don't produce warning when '-no-jdk' option is present.
Toolchain in such case should avoid setting '-jdk-home' option.

^KT-46626 In Progress
2021-07-23 08:11:02 +00:00
Mads Ager
c0f5d09759 Copy locals in addition to instructions when inlining finally blocks
^KT-46448 Fixed
2021-07-23 09:11:48 +02:00
pyos
d00fba3718 FE: avoid stack overflow on star projection of enhanced type parameter
#KT-47846 Fixed
2021-07-23 10:03:57 +03:00
Sergey Bogolepov
ed44497a9b [K/N] Prepare CallsChecker for LLVM 11.1.0
LLVM 11.1.0 adds a bit more "good" external functions and intrinsics.
2021-07-23 04:52:16 +00:00
Sergey Bogolepov
bce1075fc4 [K/N] Prepare MinGW linker for LLVM 11
Explicitly set sysroot, target and linker when linking MinGW binary
because it won't be the default target after LLVM update.
2021-07-23 04:51:52 +00:00
Sergey Bogolepov
272284680e [K/N] Prepare Windows runtime tests for LLVM update
In the upcoming LLVM update the default target for windows will be
x86_64-pc-windows-msvc and it will break runtime tests. To mitigate this
problem we explicitly set compilation target to x86_64-pc-windows-gnu
as we do in BitcodeCompiler.
2021-07-23 04:46:13 +00:00
Roman Artemev
f768d5b453 [JS TEST] Refactor test runner a bit
Build IC cache for library right after its compilation
2021-07-22 21:56:57 +03:00
Roman Artemev
0310f7cb0b [JS IC] Lot of fixes after rebase 2021-07-22 21:56:57 +03:00
Roman Artemev
8782399ffb [JS IC] Make sure already bound symbol is not being enqueued 2021-07-22 21:56:56 +03:00
Roman Artemev
334e34b70b [JS PIR] Fix inliner. Do not mutate existed statement list
Such list could be part of PIR structures
2021-07-22 21:56:56 +03:00
Anton Bannykh
20088994c1 JS IC: IC lowerings prototype 2021-07-22 21:56:55 +03:00
Anton Bannykh
525c5b886f JS IR gradle plugin: don't run IC for the main module 2021-07-22 21:56:53 +03:00
Anton Bannykh
e03cb372b7 KLIB: don't fail on invalid loops
Temporarily disable assert because this happens in lowered IR
2021-07-22 21:56:52 +03:00
Anton Bannykh
48ce8c049d JS IC: temporarily disable isPublic assert 2021-07-22 21:56:52 +03:00
Anton Bannykh
3833c833ef KLIB: changes in the .proto and linker required for the JS IC
The original behaviour is preserved. All changes should be behind the flags.
2021-07-22 21:56:51 +03:00
Anton Bannykh
002f4210f7 IR: pass information about the declaration being lowered to the infrastructure 2021-07-22 21:56:51 +03:00
Anton Bannykh
5ee865437d JS IC: expose currentDeclaration from StageController 2021-07-22 21:56:50 +03:00
Anton Bannykh
ba541bd53b IR: allow SymbolTable descendants 2021-07-22 21:56:50 +03:00
Anton Bannykh
e0570d98b2 IR: cache IdSignature hashCode for better performance in maps 2021-07-22 21:56:49 +03:00
Anton Bannykh
76f0684d7c IR: .isBound API for F/O declarations
Fake override functions and properties may not be bound to symbols.
This API allows to know if such declaration is actually bound
2021-07-22 21:56:47 +03:00
Dmitry Petrov
6c734289be JVM skip methods without NEW insns in UninitializedStoresProcessor 2021-07-22 21:29:41 +03:00
Dmitry Petrov
eff7c375ce Minor HackedFixStackMethodAnalyzerBase -> FastStackAnalyzer 2021-07-22 21:29:41 +03:00
Dmitry Petrov
aef9701661 JVM use new stack state analyzer in non-local returns preprocessing 2021-07-22 21:29:40 +03:00
Dmitry Petrov
cf2b4dd277 JVM don't use SPBs in FixStack method analyzer (we don't merge) 2021-07-22 21:29:40 +03:00
Dmitry Petrov
ca84aa4f2c JVM don't optimize if there are too many data on exception edges 2021-07-22 21:29:39 +03:00
Dmitry Petrov
c1a5ce6e61 JVM skip redundant boxing optimization in methods without boxing 2021-07-22 21:29:38 +03:00
Tianyu Geng
a8e379a025 FIR: Fix positioning of ENUM_ENTRY_AS_TYPE
The current SELECTOR_BY_QUALIFIED positioning strategy is closely
related what should be done here. But it only works on qualified access
expressions. This change also makes it work for type references.
2021-07-22 20:39:56 +03:00
Tianyu Geng
c648356887 FIR: report ENUM_ENTRY_AS_TYPE and IS_ENUM_TYPE
These two diagnostics are similar: both are reported on type references
to enum entries. But `IS_ENUM_TYPE` is reported if the type ref is an
operand of `is` operator. To pass along this contextual information, a
boolean is added to FirSpecificTypeResolverTransformer.
2021-07-22 20:39:56 +03:00
Tianyu Geng
6dc75c2e51 FIR IDE: allow KtClassOrObject to resolve to null KtSymbol
At PSI level, an enum entry is a `KtClassOrObject`. But the resolved
FIR counterpart `FirEnumEntry` is not an `FirRegularClass`.
2021-07-22 20:39:56 +03:00
Tianyu Geng
bea90e0578 FIR: remove unused diagnsotics
These diagnostics do not exist in FE1.0 and they are not used
anywhere.
2021-07-22 20:39:55 +03:00
Alexander Udalov
3b513ba299 Minor, add test on typeOf subtyping with mutable collections 2021-07-22 15:55:15 +02:00
Alexander Udalov
9ebd665c96 Report error on annotated type inside typeOf on JVM
Since it's not feasible to support annotated types in 1.6, we're making
this an explicit error in 1.6, so that typeOf can become stable and this
feature can be supported in the future without breaking changes to the
existing code.

Note that extension function types are a special case of annotated
types. A separate error is created for them just because the message
"annotated types are not supported" would be confusing, since such types
don't have explicit annotations in the source code.

 #KT-29919
2021-07-22 15:54:48 +02:00
Alexander Udalov
a383d45534 Disable -Werror if test.progressive.mode is enabled
The reason is that when advancing language version, for example from 1.5
to 1.6, there is a brief period between bootstraps where the
bootstrapped compiler has latest stable language version 1.6, yet the
project is still built with 1.5. That leads to a (correct) warning that
progressive mode makes no sense unless the latest language version is
used, which fails the build because of Werror.

When testing bootstrap in progressive mode, we don't actually care about
these warnings, so disable Werror in this case.

The only case where this could matter would be if we were introducing
_warnings_ in progressive mode and checking that there are no new
warnings on Kotlin would be important for us, but so far progressive
mode has only been used to turn already existing warnings to errors.
2021-07-22 15:41:51 +02:00
Mikhael Bogdanov
60458214a5 Update ReadMe.md 2021-07-22 12:41:34 +00:00
Elena Lepilkina
e29a67b3a3 [K/N][perf] Added autoreleasepool in swiftinterop benchmarks 2021-07-22 11:37:55 +00:00
Sergey Bogolepov
f8528c5cca [K/N] Dockerfile for building LLVM
Provide a stable environment for building LLVM for Linux
by using Docker. Note that the base image is Ubuntu 16.04,
so after LLVM update building Kotlin/Native on Linux will
require glibc 2.23 or higher.
2021-07-22 10:44:03 +00:00
Leonid Startsev
83c1a75c1e Revert "Revert "Instantiation of annotations for JVM IR with the corresponding feature flag""
Fix incorrectly rebased ce0a3a57df

This reverts commit 3d0126d5
2021-07-21 18:24:07 +03:00
Philipp Smorygo
54b9ad6bf5 Slightly improve Kotlin library podspec
Add additional parameters to Podspec for clarity.
Add ability to skip building by using an environment variable
2021-07-21 18:07:46 +03:00
Ilya Chernikov
db61665ab8 [minor] IR: clean unnecessary ObsoleteDescriptorBasedAPI opt-ins 2021-07-21 18:05:42 +03:00
Dmitriy Novozhilov
a710a8d10f [FE 1.0] Report warning on non-exhaustive when statements only after 1.6
^KT-47709
2021-07-21 17:53:05 +03:00
Igor Laevsky
865ad3698b WASM: Fix flaky test 2021-07-21 16:53:45 +03:00
Mikhael Bogdanov
d8f839a7e4 Properly process separate process inputStream/outputStream 2021-07-21 13:19:31 +00:00
Leonid Startsev
3d0126d5dd Revert "Instantiation of annotations for JVM IR with the corresponding feature flag"
because of incorrect rebase

This reverts commit ce0a3a57
2021-07-21 15:23:24 +03:00
max-kammerer
5b21444805 Update worker11.kt 2021-07-21 13:36:02 +02:00
Leonid Startsev
ce0a3a57df Instantiation of annotations for JVM IR with the corresponding feature flag
Seperate checker for platforms that do not support this language feature yet

Synthetic implementations of annotations are generated on-demand with proper 
equals, hashCode, and annotationType methods

#KT-47699 Fixed
2021-07-21 10:23:51 +00:00
Leonid Startsev
4bc521249b kotlinx.serialization: Support InheritableSerialInfo 2021-07-21 10:06:12 +00:00
Alexander Dudinsky
8eea749231 Accept android licenses in setUp PureAndroidAndJavaConsumeMppLibIT 2021-07-21 12:33:07 +03:00
Nikolay Krasko
a1a1bda5f3 Drop unused runIdeTask and excludeInAndroidStudio from localDependencies 2021-07-21 11:23:56 +02:00
Nikolay Krasko
6a0b71d3e4 Drop old IDEA run configurations 2021-07-21 11:23:56 +02:00
Nikita Bobko
d1e46e8ce7 Delete Kotlin IntelliJ IDEA plugin modules from settings.gradle 2021-07-21 11:23:53 +02:00
Nikita Bobko
39fa2b0baf Delete Kotlin IntelliJ IDEA plugin sources
Kotlin plugin sources were migrated to intellij-community:
https://github.com/JetBrains/intellij-community/tree/master/plugins/kotlin

Preserve `jps-plugin/testData/incremental`
because it's used in `compiler/incremental-compilation-impl/test`

Preserve `idea/testData/multiModuleHighlighting/multiplatform`
because it's used in `MppHighlightingTestDataWithGradleIT`
2021-07-21 11:23:43 +02:00
Elena Lepilkina
b8d74698f1 [K/N][Docs] Update HACKING.md after repositories merging and adding information about debugging and using CLion 2021-07-21 08:39:10 +00:00
Mads Ager
6436a1686d [JVM_IR] Recursively perform constant lowering.
Otherwise constants in child expressions are not transformed.

^KT-47716 Fixed.
2021-07-21 02:11:41 +02:00
Mads Ager
2877f1cabe [JVM_IR] Fix check for inline class property backing in lowering.
The inline class lowering would attempt to lower a companion object
property backing field.

^KT-47762 Fixed.
2021-07-21 01:56:46 +02:00
Dmitry Petrov
46d2e52543 JVM Minor: move uninitialized value check to stack recovery 2021-07-20 19:51:04 +03:00
Dmitry Petrov
e72d24960d JVM we don't merge frames in stack normalization 2021-07-20 19:51:03 +03:00
Dmitry Petrov
91afa3335c JVM represent uninitialized values explicitly in stack normalization 2021-07-20 19:51:02 +03:00
Dmitry Petrov
bb202318ee Minor: regenerate tests 2021-07-20 19:51:01 +03:00
Dmitry Petrov
35b4a9d4cc JVM treat all variable loads as "initialized" in stack normalization 2021-07-20 19:51:00 +03:00
Dmitry Petrov
c8b705fd2d JVM update license for HackedFixStackMethodAnalyzerBase.kt 2021-07-20 19:50:59 +03:00
Dmitry Petrov
8763235053 JVM specially hacked method analyzer for FixStack 2021-07-20 19:50:58 +03:00
Dmitry Petrov
3ecd612ce7 JVM FixStackValue & FixStackInterpreter 2021-07-20 19:50:57 +03:00
Ilya Chernikov
8eb7e719d3 [minor] fix compiler warnings in scripting modules 2021-07-20 19:42:34 +03:00
Roman Golyshev
59304ba70c FIR IDE: use correct out of block modification tracker
Follow-up to eead868cd2
2021-07-20 19:15:38 +03:00
Roman Golyshev
4e67afcaba FIR IDE: Use write lock in KtFirOverrideInfoProvider implementation
`withFir` takes read lock, but checking visibility or implementation
status actually requires resolving declaration to `STATUS` phase. But
resolve cannot be done in `withFir` function, since resolve requires
write lock, and you cannot take both read and write lock

Now we use `withFirWithPossibleResolveInside`, which takes write lock
and allows to perform resolve in it

This should fix failing `FirOverrideImplementTest` tests
in Kotlin IDE plugin
2021-07-20 19:02:26 +03:00
Roman Golyshev
f3bdadb7d9 FIR IDE: Use correct class symbol in getImplementationStatus
The previous check `if (parentClassSymbol !is FirClassSymbol<*>)`
always succeeded, because `parentClassSymbol` was a declaration,
not a symbol
2021-07-20 19:02:24 +03:00
Abduqodiri Qurbonzoda
b65c477e68 Regex.splitToSequence, CharSequence.splitToSequence(Regex) #KT-23351 2021-07-20 14:09:24 +00:00
Abduqodiri Qurbonzoda
1fee6b191f Fix typo in Sequence.constrainOnce() doc 2021-07-20 14:09:24 +00:00
Mikhael Bogdanov
ff26a471b4 Update diagnostics test affected by ApproximateIntegerLiteralTypesInReceiverPosition and ProhibitSimplificationOfNonTrivialConstBooleanExpressions features 2021-07-20 12:19:57 +00:00
Mikhael Bogdanov
fd605a13d7 Update box tests affected by ApproximateIntegerLiteralTypesInReceiverPosition feature 2021-07-20 11:42:29 +00:00
Andrey Zinovyev
6ef4523555 [FIR] Cache callable names in some composite scopes 2021-07-20 14:25:16 +03:00
Andrey Zinovyev
15be38192b [FIR] Mark implicit types in accessors as fake
To not check their types in deprecation checker
2021-07-20 14:25:14 +03:00
52055 changed files with 48987 additions and 1183311 deletions

5
.bunch
View File

@@ -1,3 +1,2 @@
202
203_202
as42
203
202

2
.idea/kotlinc.xml generated
View File

@@ -13,6 +13,6 @@
</option>
</component>
<component name="KotlinCompilerSettings">
<option name="additionalArguments" value="-version -Xallow-kotlin-package -Xskip-metadata-version-check -Xread-deserialized-contracts" />
<option name="additionalArguments" value="-version -Xallow-kotlin-package -Xskip-metadata-version-check" />
</component>
</project>

View File

@@ -1,20 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="IDEA" type="GradleRunConfiguration" factoryName="Gradle" singleton="true" folderName="IDEA">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="runIde" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<method />
</configuration>
</component>

View File

@@ -1,20 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="IDEA Ultimate" type="GradleRunConfiguration" factoryName="Gradle" folderName="IDEA">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="-P intellijUltimateEnabled" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="runUltimate" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<method />
</configuration>
</component>

View File

@@ -1,20 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="IDEA Ultimate (No ProcessCanceledException) " type="GradleRunConfiguration" factoryName="Gradle" folderName="IDEA">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="-PnoPCE" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="runUltimate" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<method />
</configuration>
</component>

View File

@@ -1,20 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="IDEA (No ProcessCanceledException)" type="GradleRunConfiguration" factoryName="Gradle" folderName="IDEA">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="-PnoPCE" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="runIde" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<method />
</configuration>
</component>

View File

@@ -1,19 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="IDEA (Not Internal)" type="GradleRunConfiguration" factoryName="Gradle" folderName="IDEA">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="-Pidea.is.internal=false" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="runIde" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
</configuration>
</component>

View File

@@ -4,7 +4,7 @@
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="--tests &quot;org.jetbrains.kotlin.gradle.CommonizerHierarchicalIT&quot; --tests &quot;org.jetbrains.kotlin.gradle.CommonizerIT&quot; --tests &quot;org.jetbrains.kotlin.commonizer.**&quot;" />
<option name="scriptParameters" value="--tests &quot;org.jetbrains.kotlin.gradle.CommonizerHierarchicalIT&quot; --tests &quot;org.jetbrains.kotlin.gradle.CommonizerIT&quot; --tests &quot;org.jetbrains.kotlin.commonizer.**&quot; --tests &quot;org.jetbrains.kotlin.gradle.native.CocoaPodsIT.testCinteropCommonization*&quot;" />
<option name="taskDescriptions">
<list />
</option>

View File

@@ -56,7 +56,7 @@ Alternatively, it is still possible to only provide required JDKs via environmen
from environmental variables - disable Gradle toolchain auto-detection by passing `-Porg.gradle.java.installations.auto-detect=false` option
(or put it into `$GRADLE_USER_HOME/gradle.properties`).
For local development, if you're not working on bytecode generation or the standard library, it's OK to avoid installing JDK 1.6 and JDK 1.7.
For local development, if you're not working on the standard library, it's OK to avoid installing JDK 1.6 and JDK 1.7.
Add `kotlin.build.isObsoleteJdkOverrideEnabled=true` to the `local.properties` file, so build will only use JDK 1.8+. Note, that in this
case, build will have Gradle remote build cache misses for some tasks.

View File

@@ -39,12 +39,11 @@ import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.org.objectweb.asm.*
import java.io.File
import java.security.MessageDigest
import java.util.*
val KOTLIN_CACHE_DIRECTORY_NAME = "kotlin"
open class IncrementalJvmCache(
private val targetDataRoot: File,
targetDataRoot: File,
targetOutputDir: File?,
pathConverter: FileToPathConverter
) : AbstractIncrementalCache<JvmClassName>(
@@ -114,32 +113,43 @@ open class IncrementalJvmCache(
}
open fun saveFileToCache(generatedClass: GeneratedJvmClass, changesCollector: ChangesCollector) {
val sourceFiles: Collection<File> = generatedClass.sourceFiles
val kotlinClass: LocalFileKotlinClass = generatedClass.outputClass
val className = kotlinClass.className
saveClassToCache(KotlinClassInfo(generatedClass.outputClass), generatedClass.sourceFiles, changesCollector)
}
/**
* Saves information about the given (kotlinc-generated) class to this cache, and stores changes between this class and its previous
* version into the given [ChangesCollector].
*
* @param kotlinClassInfo A kotlin-generated class
* @param sourceFiles The source files that the given class was generated from, or `null` if this information is not available
* @param changesCollector A [ChangesCollector]
*/
fun saveClassToCache(kotlinClassInfo: KotlinClassInfo, sourceFiles: List<File>?, changesCollector: ChangesCollector) {
val className = kotlinClassInfo.className
dirtyOutputClassesMap.notDirty(className)
sourceFiles.forEach {
sourceFiles?.forEach {
sourceToClassesMap.add(it, className)
}
internalNameToSource[className.internalName] = sourceFiles
sourceFiles?.let { internalNameToSource[className.internalName] = it }
if (kotlinClass.classId.isLocal) return
if (kotlinClassInfo.classId.isLocal) return
val header = kotlinClass.classHeader
when (header.kind) {
when (kotlinClassInfo.classKind) {
KotlinClassHeader.Kind.FILE_FACADE -> {
assert(sourceFiles.size == 1) { "Package part from several source files: $sourceFiles" }
if (sourceFiles != null) {
assert(sourceFiles.size == 1) { "Package part from several source files: $sourceFiles" }
}
packagePartMap.addPackagePart(className)
protoMap.process(kotlinClass, changesCollector)
constantsMap.process(kotlinClass, changesCollector)
inlineFunctionsMap.process(kotlinClass, changesCollector)
protoMap.process(kotlinClassInfo, changesCollector)
constantsMap.process(kotlinClassInfo, changesCollector)
inlineFunctionsMap.process(kotlinClassInfo, changesCollector)
}
KotlinClassHeader.Kind.MULTIFILE_CLASS -> {
val partNames = kotlinClass.classHeader.data?.toList()
?: throw AssertionError("Multifile class has no parts: ${kotlinClass.className}")
val partNames = kotlinClassInfo.classHeaderData?.toList()
?: throw AssertionError("Multifile class has no parts: $className")
multifileFacadeToParts[className] = partNames
// When a class is replaced with a facade with the same name,
// the class' proto wouldn't ever be deleted,
@@ -154,25 +164,29 @@ open class IncrementalJvmCache(
internalNameToSource.remove(className.internalName)
// TODO NO_CHANGES? (delegates only)
constantsMap.process(kotlinClass, changesCollector)
inlineFunctionsMap.process(kotlinClass, changesCollector)
constantsMap.process(kotlinClassInfo, changesCollector)
inlineFunctionsMap.process(kotlinClassInfo, changesCollector)
}
KotlinClassHeader.Kind.MULTIFILE_CLASS_PART -> {
assert(sourceFiles.size == 1) { "Multifile class part from several source files: $sourceFiles" }
if (sourceFiles != null) {
assert(sourceFiles.size == 1) { "Multifile class part from several source files: $sourceFiles" }
}
packagePartMap.addPackagePart(className)
partToMultifileFacade.set(className.internalName, header.multifileClassName!!)
partToMultifileFacade.set(className.internalName, kotlinClassInfo.multifileClassName!!)
protoMap.process(kotlinClass, changesCollector)
constantsMap.process(kotlinClass, changesCollector)
inlineFunctionsMap.process(kotlinClass, changesCollector)
protoMap.process(kotlinClassInfo, changesCollector)
constantsMap.process(kotlinClassInfo, changesCollector)
inlineFunctionsMap.process(kotlinClassInfo, changesCollector)
}
KotlinClassHeader.Kind.CLASS -> {
assert(sourceFiles.size == 1) { "Class is expected to have only one source file: $sourceFiles" }
addToClassStorage(kotlinClass, sourceFiles.first())
if (sourceFiles != null) {
assert(sourceFiles.size == 1) { "Class is expected to have only one source file: $sourceFiles" }
addToClassStorage(kotlinClassInfo, sourceFiles.first())
}
protoMap.process(kotlinClass, changesCollector)
constantsMap.process(kotlinClass, changesCollector)
inlineFunctionsMap.process(kotlinClass, changesCollector)
protoMap.process(kotlinClassInfo, changesCollector)
constantsMap.process(kotlinClassInfo, changesCollector)
inlineFunctionsMap.process(kotlinClassInfo, changesCollector)
}
KotlinClassHeader.Kind.UNKNOWN, KotlinClassHeader.Kind.SYNTHETIC_CLASS -> {
}
@@ -278,8 +292,8 @@ open class IncrementalJvmCache(
private inner class ProtoMap(storageFile: File) : BasicStringMap<ProtoMapValue>(storageFile, ProtoMapValueExternalizer) {
@Synchronized
fun process(kotlinClass: LocalFileKotlinClass, changesCollector: ChangesCollector) {
return put(kotlinClass, changesCollector)
fun process(kotlinClassInfo: KotlinClassInfo, changesCollector: ChangesCollector) {
return put(kotlinClassInfo, changesCollector)
}
// A module mapping (.kotlin_module file) is stored in a cache,
@@ -295,19 +309,17 @@ open class IncrementalJvmCache(
}
@Synchronized
private fun put(kotlinClass: LocalFileKotlinClass, changesCollector: ChangesCollector) {
val header = kotlinClass.classHeader
val key = kotlinClass.className.internalName
private fun put(kotlinClassInfo: KotlinClassInfo, changesCollector: ChangesCollector) {
val key = kotlinClassInfo.className.internalName
val oldData = storage[key]
val newData = ProtoMapValue(
header.kind != KotlinClassHeader.Kind.CLASS,
BitEncoding.decodeBytes(header.data!!),
header.strings!!
kotlinClassInfo.classKind != KotlinClassHeader.Kind.CLASS,
BitEncoding.decodeBytes(kotlinClassInfo.classHeaderData!!),
kotlinClassInfo.classHeaderStrings!!
)
storage[key] = newData
val packageFqName = kotlinClass.className.packageFqName
val packageFqName = kotlinClassInfo.className.packageFqName
changesCollector.collectProtoChanges(oldData?.toProtoData(packageFqName), newData.toProtoData(packageFqName), packageProtoKey = key)
}
@@ -368,31 +380,16 @@ open class IncrementalJvmCache(
// todo: reuse code with InlineFunctionsMap?
private inner class ConstantsMap(storageFile: File) : BasicStringMap<Map<String, Any>>(storageFile, ConstantsMapExternalizer) {
private fun getConstantsMap(bytes: ByteArray): Map<String, Any> {
val result = HashMap<String, Any>()
ClassReader(bytes).accept(object : ClassVisitor(Opcodes.API_VERSION) {
override fun visitField(access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor? {
val staticFinal = Opcodes.ACC_STATIC or Opcodes.ACC_FINAL or Opcodes.ACC_PRIVATE
if (value != null && access and staticFinal == Opcodes.ACC_STATIC or Opcodes.ACC_FINAL) {
result[name] = value
}
return null
}
}, ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES)
return result
}
operator fun contains(className: JvmClassName): Boolean =
className.internalName in storage
@Synchronized
fun process(kotlinClass: LocalFileKotlinClass, changesCollector: ChangesCollector) {
val key = kotlinClass.className.internalName
fun process(kotlinClassInfo: KotlinClassInfo, changesCollector: ChangesCollector) {
val key = kotlinClassInfo.className.internalName
val oldMap = storage[key] ?: emptyMap()
val newMap = getConstantsMap(kotlinClass.fileContents)
val newMap = kotlinClassInfo.constantsMap
if (newMap.isNotEmpty()) {
storage[key] = newMap
} else {
@@ -401,8 +398,18 @@ open class IncrementalJvmCache(
for (const in oldMap.keys + newMap.keys) {
//Constant can be declared via companion object or via const field declaration
changesCollector.collectMemberIfValueWasChanged(kotlinClass.scopeFqName(companion = true), const, oldMap[const], newMap[const])
changesCollector.collectMemberIfValueWasChanged(kotlinClass.scopeFqName(companion = false), const, oldMap[const], newMap[const])
changesCollector.collectMemberIfValueWasChanged(
kotlinClassInfo.scopeFqName(companion = true),
const,
oldMap[const],
newMap[const]
)
changesCollector.collectMemberIfValueWasChanged(
kotlinClassInfo.scopeFqName(companion = false),
const,
oldMap[const],
newMap[const]
)
}
}
@@ -490,67 +497,20 @@ open class IncrementalJvmCache(
value.dumpCollection()
}
private fun addToClassStorage(kotlinClass: LocalFileKotlinClass, srcFile: File) {
val (nameResolver, proto) = JvmProtoBufUtil.readClassDataFrom(kotlinClass.classHeader.data!!, kotlinClass.classHeader.strings!!)
private fun addToClassStorage(classInfo: KotlinClassInfo, srcFile: File) {
val (nameResolver, proto) = JvmProtoBufUtil.readClassDataFrom(classInfo.classHeaderData!!, classInfo.classHeaderStrings!!)
addToClassStorage(proto, nameResolver, srcFile)
}
private inner class InlineFunctionsMap(storageFile: File) :
BasicStringMap<Map<String, Long>>(storageFile, StringToLongMapExternalizer) {
private fun getInlineFunctionsMap(header: KotlinClassHeader, bytes: ByteArray): Map<String, Long> {
val inlineFunctions = inlineFunctionsJvmNames(header)
if (inlineFunctions.isEmpty()) return emptyMap()
val result = HashMap<String, Long>()
var dummyVersion: Int = -1
ClassReader(bytes).accept(object : ClassVisitor(Opcodes.API_VERSION) {
override fun visit(
version: Int,
access: Int,
name: String?,
signature: String?,
superName: String?,
interfaces: Array<out String>?
) {
super.visit(version, access, name, signature, superName, interfaces)
dummyVersion = version
}
override fun visitMethod(
access: Int,
name: String,
desc: String,
signature: String?,
exceptions: Array<out String>?
): MethodVisitor? {
val dummyClassWriter = ClassWriter(0)
dummyClassWriter.visit(dummyVersion, 0, "dummy", null, AsmTypes.OBJECT_TYPE.internalName, null)
return object : MethodVisitor(Opcodes.API_VERSION, dummyClassWriter.visitMethod(0, name, desc, null, exceptions)) {
override fun visitEnd() {
val jvmName = name + desc
if (jvmName !in inlineFunctions) return
val dummyBytes = dummyClassWriter.toByteArray()!!
val hash = dummyBytes.md5()
result[jvmName] = hash
}
}
}
}, 0)
return result
}
@Synchronized
fun process(kotlinClass: LocalFileKotlinClass, changesCollector: ChangesCollector) {
val key = kotlinClass.className.internalName
fun process(kotlinClassInfo: KotlinClassInfo, changesCollector: ChangesCollector) {
val key = kotlinClassInfo.className.internalName
val oldMap = storage[key] ?: emptyMap()
val newMap = getInlineFunctionsMap(kotlinClass.classHeader, kotlinClass.fileContents)
val newMap = kotlinClassInfo.inlineFunctionsMap
if (newMap.isNotEmpty()) {
storage[key] = newMap
} else {
@@ -559,7 +519,7 @@ open class IncrementalJvmCache(
for (fn in oldMap.keys + newMap.keys) {
changesCollector.collectMemberIfValueWasChanged(
kotlinClass.scopeFqName(),
kotlinClassInfo.scopeFqName(),
functionNameBySignature(fn),
oldMap[fn],
newMap[fn]
@@ -602,13 +562,6 @@ sealed class ChangeInfo(val fqName: FqName) {
}
}
private fun LocalFileKotlinClass.scopeFqName(companion: Boolean = false) = when (classHeader.kind) {
KotlinClassHeader.Kind.CLASS -> {
className.fqNameForClassNameWithoutDollars.let { if (companion) it.child(DEFAULT_NAME_FOR_COMPANION_OBJECT) else it }
}
else -> className.packageFqName
}
fun ByteArray.md5(): Long {
val d = MessageDigest.getInstance("MD5").digest(this)!!
return ((d[0].toLong() and 0xFFL)
@@ -640,3 +593,105 @@ fun <K : Comparable<K>, V> Map<K, V>.dumpMap(dumpValue: (V) -> String): String =
@TestOnly
fun <T : Comparable<T>> Collection<T>.dumpCollection(): String =
"[${sorted().joinToString(", ", transform = Any::toString)}]"
/**
* Minimal information about a kotlinc-generated class that will be used to compute recompilation-triggered changes to support incremental
* compilation (see [IncrementalJvmCache.saveClassToCache]).
*
* It's important that this class contain only the minimal required information, as it will be part of the classpath snapshot of the
* `KotlinCompile` task and the task needs to support compile avoidance. For example, this class should contain public method signatures,
* and should not contain private method signatures, or method implementations.
*/
class KotlinClassInfo private constructor(
val classId: ClassId,
val classKind: KotlinClassHeader.Kind,
val classHeaderData: Array<String>?,
val classHeaderStrings: Array<String>?,
@Suppress("SpellCheckingInspection") val multifileClassName: String?,
val constantsMap: LinkedHashMap<String, Any>,
val inlineFunctionsMap: LinkedHashMap<String, Long>
) {
constructor(kotlinClass: LocalFileKotlinClass) : this(
kotlinClass.classId,
kotlinClass.classHeader.kind,
kotlinClass.classHeader.data,
kotlinClass.classHeader.strings,
kotlinClass.classHeader.multifileClassName,
getConstantsMap(kotlinClass.fileContents),
getInlineFunctionsMap(kotlinClass.classHeader, kotlinClass.fileContents)
)
val className: JvmClassName by lazy { JvmClassName.byClassId(classId) }
fun scopeFqName(companion: Boolean = false) = when (classKind) {
KotlinClassHeader.Kind.CLASS -> {
className.fqNameForClassNameWithoutDollars.let { if (companion) it.child(DEFAULT_NAME_FOR_COMPANION_OBJECT) else it }
}
else -> className.packageFqName
}
}
private fun getConstantsMap(bytes: ByteArray): LinkedHashMap<String, Any> {
val result = LinkedHashMap<String, Any>()
ClassReader(bytes).accept(object : ClassVisitor(Opcodes.API_VERSION) {
override fun visitField(access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor? {
val staticFinal = Opcodes.ACC_STATIC or Opcodes.ACC_FINAL or Opcodes.ACC_PRIVATE
if (value != null && access and staticFinal == Opcodes.ACC_STATIC or Opcodes.ACC_FINAL) {
result[name] = value
}
return null
}
}, ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES)
return result
}
private fun getInlineFunctionsMap(header: KotlinClassHeader, bytes: ByteArray): LinkedHashMap<String, Long> {
val inlineFunctions = inlineFunctionsJvmNames(header)
if (inlineFunctions.isEmpty()) return LinkedHashMap()
val result = LinkedHashMap<String, Long>()
var dummyVersion: Int = -1
ClassReader(bytes).accept(object : ClassVisitor(Opcodes.API_VERSION) {
override fun visit(
version: Int,
access: Int,
name: String?,
signature: String?,
superName: String?,
interfaces: Array<out String>?
) {
super.visit(version, access, name, signature, superName, interfaces)
dummyVersion = version
}
override fun visitMethod(
access: Int,
name: String,
desc: String,
signature: String?,
exceptions: Array<out String>?
): MethodVisitor {
val dummyClassWriter = ClassWriter(0)
dummyClassWriter.visit(dummyVersion, 0, "dummy", null, AsmTypes.OBJECT_TYPE.internalName, null)
return object : MethodVisitor(Opcodes.API_VERSION, dummyClassWriter.visitMethod(0, name, desc, null, exceptions)) {
override fun visitEnd() {
val jvmName = name + desc
if (jvmName !in inlineFunctions) return
val dummyBytes = dummyClassWriter.toByteArray()!!
val hash = dummyBytes.md5()
result[jvmName] = hash
}
}
}
}, 0)
return result
}

View File

@@ -126,7 +126,7 @@ open class LookupStorage(
countersFile.createNewFile()
}
countersFile.writeText("$size\n")
countersFile.writeText("$size\n0")
}
} finally {
super.flush(memoryCachesOnly)

View File

@@ -148,11 +148,9 @@ extra["versions.kotlinx-collections-immutable-jvm"] = immutablesVersion
extra["versions.ktor-network"] = "1.0.1"
if (!project.hasProperty("versions.kotlin-native")) {
extra["versions.kotlin-native"] = "1.6.0-dev-248"
extra["versions.kotlin-native"] = "1.6.0-dev-1728"
}
val effectSystemEnabled by extra(project.getBooleanProperty("kotlin.compiler.effectSystemEnabled") ?: false)
val newInferenceEnabled by extra(project.getBooleanProperty("kotlin.compiler.newInferenceEnabled") ?: false)
val useJvmFir by extra(project.kotlinBuildProperties.useFir)
val intellijSeparateSdks = project.getBooleanProperty("intellijSeparateSdks") ?: false
@@ -161,11 +159,7 @@ extra["intellijSeparateSdks"] = intellijSeparateSdks
extra["IntellijCoreDependencies"] =
listOf(
when {
Platform[203].orHigher() -> "asm-all-9.0"
Platform[202].orHigher() -> "asm-all-8.0.1"
else -> "asm-all-7.0.1"
},
"asm-all-9.0",
"guava",
"jdom",
"jna",
@@ -451,7 +445,6 @@ allprojects {
val commonCompilerArgs = listOfNotNull(
"-Xopt-in=kotlin.RequiresOptIn",
"-Xread-deserialized-contracts",
"-progressive".takeIf { hasProperty("test.progressive.mode") }
)
@@ -467,7 +460,7 @@ allprojects {
"-Xjvm-default=compatibility",
"-Xno-optimized-callable-references",
"-Xno-kotlin-nothing-value-exception",
"-Xnormalize-constructor-calls=enable"
"-Xsuppress-deprecated-jvm-target-warning" // Remove as soon as there are no modules for JDK 1.6 & 1.7
)
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile> {
@@ -481,7 +474,7 @@ allprojects {
}
}
if (!kotlinBuildProperties.isInJpsBuildIdeaSync && !kotlinBuildProperties.useFir && !kotlinBuildProperties.disableWerror) {
if (!kotlinBuildProperties.disableWerror) {
// For compiler and stdlib, allWarningsAsErrors is configured in the corresponding "root" projects
// (compiler/build.gradle.kts and libraries/commonConfiguration.gradle).
val projectsWithWarningsAsErrors = listOf("core", "plugins").map { File(it).absoluteFile }
@@ -734,14 +727,8 @@ tasks {
dependsOn(":kotlin-scripting-jsr223-test:embeddableTest")
dependsOn(":kotlin-main-kts-test:test")
dependsOn(":kotlin-main-kts-test:testWithIr")
if (kotlinBuildProperties.getOrNull("attachedIntellijVersion") == null &&
!kotlinBuildProperties.getBoolean("disableKotlinPluginModules", false)
) {
dependsOn(":kotlin-scripting-ide-services-test:test")
dependsOn(":kotlin-scripting-ide-services-test:embeddableTest")
}
dependsOn(":kotlin-scripting-ide-services-test:test")
dependsOn(":kotlin-scripting-ide-services-test:embeddableTest")
dependsOn(":kotlin-scripting-js-test:test")
}
@@ -1145,4 +1132,4 @@ afterEvaluate {
"https://cache-redirector.jetbrains.com/github.com/yarnpkg/yarn/releases/download"
}
}
}
}

View File

@@ -19,7 +19,8 @@ val KotlinBuildProperties.jarCompression: Boolean get() = getBoolean("kotlin.bui
val KotlinBuildProperties.ignoreTestFailures: Boolean get() = getBoolean("ignoreTestFailures", isTeamcityBuild)
val KotlinBuildProperties.disableWerror: Boolean get() = getBoolean("kotlin.build.disable.werror", false)
val KotlinBuildProperties.disableWerror: Boolean
get() = getBoolean("kotlin.build.disable.werror") || useFir || isInJpsBuildIdeaSync || getBoolean("test.progressive.mode")
val KotlinBuildProperties.isObsoleteJdkOverrideEnabled: Boolean
get() = getBoolean("kotlin.build.isObsoleteJdkOverrideEnabled", false)

View File

@@ -26,7 +26,7 @@ fun CompatibilityPredicate.or(other: CompatibilityPredicate): CompatibilityPredi
}
enum class Platform : CompatibilityPredicate {
P202, P203;
P203;
val version: Int = name.drop(1).toInt()
@@ -43,10 +43,7 @@ enum class Platform : CompatibilityPredicate {
}
enum class Ide(val platform: Platform) : CompatibilityPredicate {
IJ202(Platform.P202),
IJ203(Platform.P203),
AS42(Platform.P202);
IJ203(Platform.P203);
val kind = Kind.values().first { it.shortName == name.take(2) }
val version = name.dropWhile { !it.isDigit() }.toInt()

View File

@@ -22,7 +22,8 @@ enum class JdkMajorVersion(
JDK_10(10, mandatory = false, overrideMajorVersion = 11),
JDK_11(11, mandatory = false),
JDK_15(15, mandatory = false),
JDK_16(16, mandatory = false);
JDK_16(16, mandatory = false),
JDK_17(17, mandatory = false);
fun isMandatory(): Boolean = mandatory
@@ -180,4 +181,4 @@ fun Project.getJdkVersionWithOverride(jdkVersion: JdkMajorVersion): JdkMajorVers
} else {
jdkVersion
}
}
}

View File

@@ -9,12 +9,8 @@ import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.kotlin.dsl.extra
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.provideDelegate
import org.gradle.kotlin.dsl.withType
import org.gradle.process.CommandLineArgumentProvider
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@JvmOverloads
fun Project.configureJava9Compilation(
@@ -59,17 +55,3 @@ private class Java9AdditionalArgumentsProvider(
"-Xlint:-requires-transitive-automatic" // suppress automatic module transitive dependencies in kotlin.test
)
}
fun Project.disableDeprecatedJvmTargetWarning() {
if (!kotlinBuildProperties.useFir && !kotlinBuildProperties.disableWerror) {
val tasksWithWarnings: List<String> by rootProject.extra
tasks.withType<KotlinCompile>().configureEach {
if (!tasksWithWarnings.contains(path)) {
kotlinOptions {
allWarningsAsErrors = true
freeCompilerArgs += "-Xsuppress-deprecated-jvm-target-warning"
}
}
}
}
}

View File

@@ -37,8 +37,8 @@ configurations {
}
tasks.withType<KotlinCompile> {
kotlinOptions.languageVersion = "1.3"
kotlinOptions.apiVersion = "1.3"
kotlinOptions.languageVersion = "1.4"
kotlinOptions.apiVersion = "1.4"
kotlinOptions.freeCompilerArgs += listOf(
"-Xskip-prerelease-check",
"-Xskip-runtime-version-check",

View File

@@ -17,16 +17,11 @@
// usages in build scripts are not tracked properly
@file:Suppress("unused")
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.artifacts.dsl.RepositoryHandler
import org.gradle.api.artifacts.repositories.IvyArtifactRepository
import org.gradle.api.tasks.JavaExec
import org.gradle.api.tasks.TaskProvider
import org.gradle.kotlin.dsl.DependencyHandlerScope
import org.gradle.kotlin.dsl.extra
import org.gradle.kotlin.dsl.register
import java.io.File
private fun Project.kotlinBuildLocalDependenciesDir(): File =
@@ -146,70 +141,4 @@ fun ModuleDependency.includeIntellijCoreJarDependencies(project: Project, jarsFi
rootProject = project.rootProject
)
fun Project.intellijRootDir() = IntellijRootUtils.getIntellijRootDir(project)
fun DependencyHandlerScope.excludeInAndroidStudio(rootProject: Project, block: DependencyHandlerScope.() -> Unit) {
if (!rootProject.extra.has("versions.androidStudioRelease")) {
block()
}
}
fun Project.runIdeTask(name: String, ideaPluginDir: File, ideaSandboxDir: File, body: JavaExec.() -> Unit): TaskProvider<JavaExec> {
return tasks.register<JavaExec>(name) {
val ideaSandboxConfigDir = File(ideaSandboxDir, "config")
classpath = mainSourceSet.runtimeClasspath
mainClass.set("com.intellij.idea.Main")
workingDir = File(intellijRootDir(), "bin")
jvmArgs(
"-Xmx1250m",
"-XX:ReservedCodeCacheSize=240m",
"-XX:+HeapDumpOnOutOfMemoryError",
"-ea",
"-Didea.debug.mode=true",
"-Didea.system.path=$ideaSandboxDir",
"-Didea.config.path=$ideaSandboxConfigDir",
"-Didea.tooling.debug=true",
"-Dfus.internal.test.mode=true",
"-Dapple.laf.useScreenMenuBar=true",
"-Dapple.awt.graphics.UseQuartz=true",
"-Dsun.io.useCanonCaches=false",
"-Dplugin.path=${ideaPluginDir.absolutePath}"
)
jvmArgs("-Didea.platform.prefix=Idea")
if (rootProject.findProperty("versions.androidStudioRelease") != null) {
jvmArgs("-Didea.platform.prefix=AndroidStudio")
}
if (project.hasProperty("noPCE")) {
jvmArgs("-Didea.ProcessCanceledException=disabled")
}
jvmArgs("-Didea.is.internal=${project.findProperty("idea.is.internal") ?: true}")
project.findProperty("idea.args")?.let { arguments ->
jvmArgs(arguments.toString().split(" "))
}
args()
doFirst {
val disabledPluginsFile = File(ideaSandboxConfigDir, "disabled_plugins.txt")
val disabledPluginsContents = disabledPluginsFile.takeIf { it.isFile }?.readLines()
val filteredContents = disabledPluginsContents?.filterNot { it.contains("org.jetbrains.kotlin") }
if (filteredContents != null && filteredContents.size != disabledPluginsContents.size) {
with(disabledPluginsFile.printWriter()) {
filteredContents.forEach(this::println)
}
}
}
body()
}
}
fun Project.intellijRootDir() = IntellijRootUtils.getIntellijRootDir(project)

View File

@@ -171,16 +171,18 @@ fun Project.configureDefaultPublishing() {
.all { configureRepository() }
}
private fun Project.getSensitiveProperty(name: String): String? {
return project.findProperty(name) as? String ?: System.getenv(name)
}
private fun Project.configureSigning() {
configure<SigningExtension> {
sign(extensions.getByType<PublishingExtension>().publications) // all publications
val signKeyId = project.findProperty("signKeyId") as? String
val signKeyId = project.getSensitiveProperty("signKeyId")
if (!signKeyId.isNullOrBlank()) {
val signKeyPrivate = project.findProperty("signKeyPrivate") as? String
?: error("Parameter `signKeyPrivate` not found")
val signKeyPassphrase = project.findProperty("signKeyPassphrase") as? String
?: error("Parameter `signKeyPassphrase` not found")
val signKeyPrivate = project.getSensitiveProperty("signKeyPrivate") ?: error("Parameter `signKeyPrivate` not found")
val signKeyPassphrase = project.getSensitiveProperty("signKeyPassphrase") ?: error("Parameter `signKeyPassphrase` not found")
useInMemoryPgpKeys(signKeyId, signKeyPrivate, signKeyPassphrase)
} else {
useGpgCmd()

View File

@@ -15,7 +15,10 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.codegen.CodegenTestFiles
import org.jetbrains.kotlin.codegen.GenerationUtils
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.psi.KtFile
@@ -23,11 +26,11 @@ import org.jetbrains.kotlin.test.*
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.model.DependencyKind
import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.model.ResultingArtifact
import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerTest
import org.jetbrains.kotlin.test.services.*
import org.jetbrains.kotlin.test.services.configuration.CommonEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.configuration.JvmEnvironmentConfigurator
import org.jetbrains.kotlin.test.services.impl.BackendKindExtractorImpl
import org.jetbrains.kotlin.test.services.impl.TemporaryDirectoryManagerImpl
import org.jetbrains.kotlin.test.services.sourceProviders.AdditionalDiagnosticsSourceFilesProvider
import org.jetbrains.kotlin.test.services.sourceProviders.CodegenHelpersSourceFilesProvider
@@ -382,6 +385,7 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
"test${testDataFile.nameWithoutExtension.replaceFirstChar(Char::uppercaseChar)}",
emptySet()
)
startingArtifactFactory = { ResultingArtifact.Source() }
}.build(testDataFile.path)
}
@@ -406,7 +410,6 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
assertions = JUnit5Assertions
useAdditionalService<TemporaryDirectoryManager>(::TemporaryDirectoryManagerImpl)
useAdditionalService<BackendKindExtractor>(::BackendKindExtractorImpl)
useSourcePreprocessor(*AbstractKotlinCompilerTest.defaultPreprocessors.toTypedArray())
useDirectives(*AbstractKotlinCompilerTest.defaultDirectiveContainers.toTypedArray())
}

View File

@@ -87,7 +87,7 @@ class StringConcatGenerator(val mode: JvmStringConcat, val mv: InstructionAdapte
paramTypes.add(type)
paramSlots += type.size
template.append("\u0001")
if (paramSlots >= 200) {
if (paramSlots >= 199) {
// Concatenate current arguments into string
// because of `StringConcatFactory` limitation add use it as new argument for further processing:
// "The number of parameter slots in {@code concatType} is less than or equal to 200"
@@ -166,4 +166,4 @@ class StringConcatGenerator(val mode: JvmStringConcat, val mv: InstructionAdapte
StringConcatGenerator(state.runtimeStringConcat, mv)
}
}
}

View File

@@ -1288,8 +1288,8 @@ private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction:
fun nextLabel(node: AbstractInsnNode?): LabelNode? {
var current = node
while (current != null) {
if (current is LabelNode) return current
current = current.next
if (current is LabelNode) return current as LabelNode
current = current!!.next
}
return null
}
@@ -1302,6 +1302,8 @@ private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction:
oldLvt += record
}
method.localVariables.clear()
val oldLvtNodeToLatestNewLvtNode = mutableMapOf<LocalVariableNode, LocalVariableNode>()
// Skip `this` for suspend lambda
val start = if (isForNamedFunction) 0 else 1
for (variableIndex in start until method.maxLocals) {
@@ -1341,33 +1343,41 @@ private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction:
val endLabel = nextLabel(insn.next)?.let { min(lvtRecord.end, it) } ?: lvtRecord.end
// startLabel can be null in case of parameters
@Suppress("NAME_SHADOWING") val startLabel = startLabel ?: lvtRecord.start
val node = LocalVariableNode(lvtRecord.name, lvtRecord.desc, lvtRecord.signature, startLabel, endLabel, lvtRecord.index)
method.localVariables.add(node)
// Attempt to extend existing local variable node corresponding to the record in
// the original local variable table, if there is no back-edge
val recordToExtend: LocalVariableNode? = oldLvtNodeToLatestNewLvtNode[lvtRecord]
var recordExtended = false
if (recordToExtend != null) {
var hasBackEdgeOrStore = false
var current: AbstractInsnNode? = recordToExtend.end
while (current != null && current != endLabel) {
if (current is JumpInsnNode) {
if (method.instructions.indexOf((current as JumpInsnNode).label) < method.instructions.indexOf(current)) {
hasBackEdgeOrStore = true
break
}
}
if (current!!.isStoreOperation() && (current as VarInsnNode).`var` == recordToExtend.index) {
hasBackEdgeOrStore = true
break
}
current = current!!.next
}
if (!hasBackEdgeOrStore) {
recordToExtend.end = endLabel
recordExtended = true
}
}
if (!recordExtended) {
val node = LocalVariableNode(lvtRecord.name, lvtRecord.desc, lvtRecord.signature, startLabel, endLabel, lvtRecord.index)
method.localVariables.add(node)
oldLvtNodeToLatestNewLvtNode[lvtRecord] = node
}
}
}
}
// Merge consequent LVT records, otherwise, atomicfu goes crazy (KT-47749)
val toRemove = arrayListOf<LocalVariableNode>()
val sortedLVT = method.localVariables.sortedBy { method.instructions.indexOf(it.start) }
for (i in sortedLVT.indices) {
var endIndex = method.instructions.indexOf(sortedLVT[i].end)
for (j in (i + 1) until sortedLVT.size) {
val startIndex = method.instructions.indexOf(sortedLVT[j].start)
if (endIndex < startIndex) break
if (endIndex != startIndex ||
sortedLVT[i].index != sortedLVT[j].index ||
sortedLVT[i].name != sortedLVT[j].name ||
sortedLVT[i].desc != sortedLVT[j].desc
) continue
sortedLVT[i].end = sortedLVT[j].end
endIndex = method.instructions.indexOf(sortedLVT[j].end)
toRemove += sortedLVT[j]
}
}
method.localVariables.removeAll(toRemove)
for (variable in oldLvt) {
// $continuation and $result are dead, but they are used by debugger, as well as fake inliner variables
// For example, $continuation is used to create async stack trace

View File

@@ -73,8 +73,8 @@ import kotlin.math.max
* - restore constructor arguments
*/
class UninitializedStoresProcessor(
private val methodNode: MethodNode,
private val shouldPreserveClassInitialization: Boolean
private val methodNode: MethodNode,
private val shouldPreserveClassInitialization: Boolean
) {
// <init> method is "special", because it will invoke <init> from this class or from a base class for #0
//
@@ -87,10 +87,10 @@ class UninitializedStoresProcessor(
fun run() {
val interpreter = UninitializedNewValueMarkerInterpreter(methodNode.instructions)
val frames = CustomFramesMethodAnalyzer(
"fake", methodNode, interpreter,
this::UninitializedNewValueFrame
).analyze()
if (methodNode.instructions.toArray().none { it.opcode == Opcodes.NEW })
return
val frames = CustomFramesMethodAnalyzer("fake", methodNode, interpreter, this::UninitializedNewValueFrame).analyze()
interpreter.analyzePopInstructions(frames)
@@ -115,12 +115,12 @@ class UninitializedStoresProcessor(
// POP
val typeNameForClass = newInsn.desc.replace('/', '.')
insertBefore(newInsn, LdcInsnNode(typeNameForClass))
insertBefore(newInsn, MethodInsnNode(
Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false
))
insertBefore(
newInsn,
MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false)
)
set(newInsn, InsnNode(Opcodes.POP))
}
else {
} else {
remove(newInsn)
}
}
@@ -138,10 +138,7 @@ class UninitializedStoresProcessor(
}
methodNode.maxLocals = max(methodNode.maxLocals, nextVarIndex)
methodNode.instructions.insertBefore(insn, insnListOf(
TypeInsnNode(Opcodes.NEW, newInsn.desc),
InsnNode(Opcodes.DUP)
))
methodNode.instructions.insertBefore(insn, insnListOf(TypeInsnNode(Opcodes.NEW, newInsn.desc), InsnNode(Opcodes.DUP)))
for (type in storedTypes.reversed()) {
nextVarIndex -= type.size
@@ -174,11 +171,11 @@ class UninitializedStoresProcessor(
assert(insn.opcode == Opcodes.INVOKESPECIAL) { "Expected opcode Opcodes.INVOKESPECIAL for <init>, but ${insn.opcode} found" }
val paramsCountIncludingReceiver = Type.getArgumentTypes((insn as MethodInsnNode).desc).size + 1
val newValue = peek(paramsCountIncludingReceiver) as? UninitializedNewValue ?:
if (isInSpecialMethod)
return null
else
error("Expected value generated with NEW")
val newValue = peek(paramsCountIncludingReceiver) as? UninitializedNewValue
?: if (isInSpecialMethod)
return null
else
error("Expected value generated with NEW")
assert(peek(paramsCountIncludingReceiver - 1) is UninitializedNewValue) {
"Next value after NEW should be one generated by DUP"
@@ -188,8 +185,8 @@ class UninitializedStoresProcessor(
}
private class UninitializedNewValue(
val newInsn: TypeInsnNode,
val internalName: String
val newInsn: TypeInsnNode,
val internalName: String
) : StrictBasicValue(Type.getObjectType(internalName)) {
override fun toString() = "UninitializedNewValue(internalName='$internalName')"
}
@@ -236,7 +233,8 @@ class UninitializedStoresProcessor(
private fun checkUninitializedObjectCopy(newInsn: TypeInsnNode, usageInsn: AbstractInsnNode) {
when (usageInsn.opcode) {
Opcodes.DUP, Opcodes.ASTORE, Opcodes.ALOAD -> {}
Opcodes.DUP, Opcodes.ASTORE, Opcodes.ALOAD -> {
}
else -> error("Unexpected copy instruction for ${newInsn.debugText}: ${usageInsn.debugText}")
}
}

View File

@@ -320,7 +320,8 @@ class AnonymousObjectTransformer(
inliningContext.callSiteInfo.isInlineOrInsideInline,
inliningContext.callSiteInfo.file,
inliningContext.callSiteInfo.lineNumber
), null
),
null
).doInline(deferringVisitor, LocalVarRemapper(parameters, 0), false, mapOf())
reifiedTypeParametersUsages?.let(result.reifiedTypeParametersUsages::mergeAll)
deferringVisitor.visitMaxs(-1, -1)

View File

@@ -187,6 +187,9 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
val splitBy = SimpleInterval(start.info as LabelNode, extension.finallyIntervalEnd)
processor.tryBlocksMetaInfo.splitAndRemoveCurrentIntervals(splitBy, true)
processor.localVarsMetaInfo.splitAndRemoveCurrentIntervals(splitBy, true)
finallyNode.localVariables.forEach {
processor.localVarsMetaInfo.addNewInterval(LocalVarNodeWrapper(it))
}
}
curInstr = curInstr.next

View File

@@ -13,12 +13,8 @@ import org.jetbrains.kotlin.codegen.inline.coroutines.markNoinlineLambdaIfSuspen
import org.jetbrains.kotlin.codegen.inline.coroutines.surroundInvokesWithSuspendMarkersIfNeeded
import org.jetbrains.kotlin.codegen.optimization.ApiVersionCallsPreprocessingMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.FixStackWithLabelNormalizationMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.common.ControlFlowGraph
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.common.*
import org.jetbrains.kotlin.codegen.optimization.fixStack.*
import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNotNull
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
import org.jetbrains.kotlin.config.LanguageFeature
@@ -36,8 +32,6 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.commons.LocalVariablesSorter
import org.jetbrains.org.objectweb.asm.commons.MethodRemapper
import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicInterpreter
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
import org.jetbrains.org.objectweb.asm.util.Printer
import java.util.*
@@ -57,8 +51,10 @@ class MethodInliner(
) {
private val languageVersionSettings = inliningContext.state.languageVersionSettings
private val invokeCalls = ArrayList<InvokeCall>()
//keeps order
private val transformations = ArrayList<TransformationInfo>()
//current state
private val currentTypeMapping = HashMap<String, String?>()
private val result = InlineResult.create()
@@ -273,7 +269,8 @@ class MethodInliner(
val varRemapper = LocalVarRemapper(lambdaParameters, valueParamShift)
//TODO add skipped this and receiver
val lambdaResult = inliner.doInline(localVariablesSorter, varRemapper, true, info.returnLabels, invokeCall.finallyDepthShift)
val lambdaResult =
inliner.doInline(localVariablesSorter, varRemapper, true, info.returnLabels, invokeCall.finallyDepthShift)
result.mergeWithNotChangeInfo(lambdaResult)
result.reifiedTypeParametersUsages.mergeAll(lambdaResult.reifiedTypeParametersUsages)
result.reifiedTypeParametersUsages.mergeAll(info.reifiedTypeParametersUsages)
@@ -303,7 +300,7 @@ class MethodInliner(
} else capturedParamDesc
visitFieldInsn(
Opcodes.GETSTATIC, realDesc.containingLambdaName,
FieldRemapper.foldName(realDesc.fieldName), realDesc.type.descriptor
foldName(realDesc.fieldName), realDesc.type.descriptor
)
}
super.visitMethodInsn(opcode, info.newClassName, name, info.newConstructorDescriptor, itf)
@@ -441,7 +438,7 @@ class MethodInliner(
else -> ""
}
val varName = if (!varSuffix.isEmpty() && name == AsmUtil.THIS) AsmUtil.INLINE_DECLARATION_SITE_THIS else name
val varName = if (varSuffix.isNotEmpty() && name == AsmUtil.THIS) AsmUtil.INLINE_DECLARATION_SITE_THIS else name
super.visitLocalVariable(varName + varSuffix, desc, signature, start, end, getNewIndex(index))
}
}
@@ -533,33 +530,37 @@ class MethodInliner(
cur.opcode == Opcodes.GETSTATIC -> {
val fieldInsnNode = cur as FieldInsnNode?
val className = fieldInsnNode!!.owner
if (isAnonymousSingletonLoad(className, fieldInsnNode.name)) {
recordTransformation(
AnonymousObjectTransformationInfo(
className, awaitClassReification, isAlreadyRegenerated(className), true,
inliningContext.nameGenerator
when {
isAnonymousSingletonLoad(className, fieldInsnNode.name) -> {
recordTransformation(
AnonymousObjectTransformationInfo(
className, awaitClassReification, isAlreadyRegenerated(className), true,
inliningContext.nameGenerator
)
)
)
awaitClassReification = false
} else if (isWhenMappingAccess(className, fieldInsnNode.name)) {
recordTransformation(
WhenMappingTransformationInfo(
className, inliningContext.nameGenerator, isAlreadyRegenerated(className), fieldInsnNode
awaitClassReification = false
}
isWhenMappingAccess(className, fieldInsnNode.name) -> {
recordTransformation(
WhenMappingTransformationInfo(
className, inliningContext.nameGenerator, isAlreadyRegenerated(className), fieldInsnNode
)
)
)
} else if (fieldInsnNode.isCheckAssertionsStatus()) {
fieldInsnNode.owner = inlineCallSiteInfo.ownerClassName
when {
// In inline function itself:
inliningContext.parent == null -> inliningContext
// In method of regenerated object - field should already exist:
inliningContext.parent is RegeneratedClassContext -> inliningContext.parent
// In lambda inlined into the root function:
inliningContext.parent.parent == null -> inliningContext.parent
// In lambda inlined into a method of a regenerated object:
else -> inliningContext.parent.parent as? RegeneratedClassContext
?: throw AssertionError("couldn't find class for \$assertionsDisabled (context = $inliningContext)")
}.generateAssertField = true
}
fieldInsnNode.isCheckAssertionsStatus() -> {
fieldInsnNode.owner = inlineCallSiteInfo.ownerClassName
when {
// In inline function itself:
inliningContext.parent == null -> inliningContext
// In method of regenerated object - field should already exist:
inliningContext.parent is RegeneratedClassContext -> inliningContext.parent
// In lambda inlined into the root function:
inliningContext.parent.parent == null -> inliningContext.parent
// In lambda inlined into a method of a regenerated object:
else -> inliningContext.parent.parent as? RegeneratedClassContext
?: throw AssertionError("couldn't find class for \$assertionsDisabled (context = $inliningContext)")
}.generateAssertField = true
}
}
}
@@ -588,7 +589,7 @@ class MethodInliner(
assert(lambdaInfo.lambdaClassType.internalName == nodeRemapper.originalLambdaInternalName) {
"Wrong bytecode template for contract template: ${lambdaInfo.lambdaClassType.internalName} != ${nodeRemapper.originalLambdaInternalName}"
}
fieldInsn.name = FieldRemapper.foldName(fieldInsn.name)
fieldInsn.name = foldName(fieldInsn.name)
fieldInsn.opcode = Opcodes.PUTSTATIC
toDelete.addAll(stackTransformations)
}
@@ -742,7 +743,9 @@ class MethodInliner(
ApiVersionCallsPreprocessingMethodTransformer(targetApiVersion).transform("fake", node)
}
val frames = analyzeMethodNodeWithInterpreter(node, BasicInterpreter())
removeFakeVariablesInitializationIfPresent(node)
val frames = FastStackAnalyzer("<fake>", node, FixStackInterpreter()).analyze()
val localReturnsNormalizer = LocalReturnsNormalizer()
@@ -764,6 +767,73 @@ class MethodInliner(
localReturnsNormalizer.transform(node)
}
private fun removeFakeVariablesInitializationIfPresent(node: MethodNode) {
// Before 1.6, we generated fake variable initialization instructions
// ICONST_0
// ISTORE x
// for all inline functions. Original intent was to mark inline function body for the debugger with corresponding LVT entry.
// However, for @InlineOnly functions corresponding LVT entries were not copied (assuming that nobody is actually debugging
// @InlineOnly functions).
// Since 1.6, we no longer generate fake variables for @InlineOnly functions
// Here we erase fake variable initialization for @InlineOnly functions inlined into existing bytecode (e.g., inline function
// inside third-party library).
// We consider a sequence of instructions 'ICONST_0; ISTORE x' a fake variable initialization if the corresponding variable 'x'
// is not used in the bytecode (see below).
val insnArray = node.instructions.toArray()
// Very conservative variable usage check.
// Here we look at integer variables only (this includes integral primitive types: byte, char, short, boolean).
// Variable is considered "used" if:
// - it's loaded with ILOAD instruction
// - it's incremented with IINC instruction
// - there's a local variable table entry for this variable
val usedIntegerVar = BooleanArray(node.maxLocals)
for (insn in insnArray) {
if (insn.type == AbstractInsnNode.VAR_INSN && insn.opcode == Opcodes.ILOAD) {
usedIntegerVar[(insn as VarInsnNode).`var`] = true
} else if (insn.type == AbstractInsnNode.IINC_INSN) {
usedIntegerVar[(insn as IincInsnNode).`var`] = true
}
}
for (localVariable in node.localVariables) {
val d0 = localVariable.desc[0]
// byte || char || short || int || boolean
if (d0 == 'B' || d0 == 'C' || d0 == 'S' || d0 == 'I' || d0 == 'Z') {
usedIntegerVar[localVariable.index] = true
}
}
// Looking for sequences of instructions:
// p0: ICONST_0
// p1: ISTORE x
// p2: <label>
// If variable 'x' is not "used" (see above), remove p0 and p1 instructions.
var changes = false
for (p0 in insnArray) {
if (p0.opcode != Opcodes.ICONST_0) continue
val p1 = p0.next ?: break
if (p1.opcode != Opcodes.ISTORE) continue
val p2 = p1.next ?: break
if (p2.type != AbstractInsnNode.LABEL) continue
val varIndex = (p1 as VarInsnNode).`var`
if (!usedIntegerVar[varIndex]) {
changes = true
node.instructions.remove(p0)
node.instructions.remove(p1)
}
}
if (changes) {
// If we removed some instructions, some TCBs could (in theory) become empty.
// Remove empty TCBs if there are any.
node.removeEmptyCatchBlocks()
}
}
private fun isAnonymousClassThatMustBeRegenerated(type: Type?): Boolean {
if (type == null || type.sort != Type.OBJECT) return false
return inliningContext.isRegeneratedAnonymousObject(type.internalName)
@@ -831,9 +901,9 @@ class MethodInliner(
if (inliningContext.isInliningLambda && inliningContext.lambdaInfo is IrExpressionLambda && !inliningContext.parent!!.isInliningLambda) {
val capturedVars = inliningContext.lambdaInfo.capturedVars
var offset = parameters.realParametersSizeOnStack
val map = capturedVars.map {
val map = capturedVars.associate {
offset to it.also { offset += it.type.size }
}.toMap()
}
var cur: AbstractInsnNode? = node.instructions.first
while (cur != null) {
@@ -878,6 +948,7 @@ class MethodInliner(
}
}
@Suppress("SameParameterValue")
private fun wrapException(originalException: Throwable, node: MethodNode, errorSuffix: String): RuntimeException {
return if (originalException is InlineException) {
InlineException("$errorPrefix: $errorSuffix", originalException)
@@ -890,7 +961,7 @@ class MethodInliner(
private class LocalReturn(
private val returnInsn: AbstractInsnNode,
private val insertBeforeInsn: AbstractInsnNode,
private val frame: Frame<BasicValue>
private val frame: Frame<FixStackValue>
) {
fun transform(insnList: InsnList, returnVariableIndex: Int) {
@@ -901,22 +972,19 @@ class MethodInliner(
if (expectedStackSize == actualStackSize) return
var stackSize = actualStackSize
val topValue = frame.getStack(stackSize - 1)
if (isReturnWithValue) {
val storeOpcode = Opcodes.ISTORE + returnInsn.opcode - Opcodes.IRETURN
insnList.insertBefore(insertBeforeInsn, VarInsnNode(storeOpcode, returnVariableIndex))
insnList.insertBefore(insertBeforeInsn, VarInsnNode(topValue.storeOpcode, returnVariableIndex))
stackSize--
}
while (stackSize > 0) {
val stackElementSize = frame.getStack(stackSize - 1).size
val popOpcode = if (stackElementSize == 1) Opcodes.POP else Opcodes.POP2
insnList.insertBefore(insertBeforeInsn, InsnNode(popOpcode))
insnList.insertBefore(insertBeforeInsn, InsnNode(frame.getStack(stackSize - 1).popOpcode))
stackSize--
}
if (isReturnWithValue) {
val loadOpcode = Opcodes.ILOAD + returnInsn.opcode - Opcodes.IRETURN
insnList.insertBefore(insertBeforeInsn, VarInsnNode(loadOpcode, returnVariableIndex))
insnList.insertBefore(insertBeforeInsn, VarInsnNode(topValue.loadOpcode, returnVariableIndex))
}
}
}
@@ -926,10 +994,10 @@ class MethodInliner(
private var returnVariableSize = 0
private var returnOpcode = -1
internal fun addLocalReturnToTransform(
fun addLocalReturnToTransform(
returnInsn: AbstractInsnNode,
insertBeforeInsn: AbstractInsnNode,
sourceValueFrame: Frame<BasicValue>
sourceValueFrame: Frame<FixStackValue>
) {
assert(isReturnOpcode(returnInsn.opcode)) { "return instruction expected" }
assert(returnOpcode < 0 || returnOpcode == returnInsn.opcode) { "Return op should be " + Printer.OPCODES[returnOpcode] + ", got " + Printer.OPCODES[returnInsn.opcode] }
@@ -938,11 +1006,7 @@ class MethodInliner(
localReturns.add(LocalReturn(returnInsn, insertBeforeInsn, sourceValueFrame))
if (returnInsn.opcode != Opcodes.RETURN) {
returnVariableSize = if (returnInsn.opcode == Opcodes.LRETURN || returnInsn.opcode == Opcodes.DRETURN) {
2
} else {
1
}
returnVariableSize = if (returnInsn.opcode == Opcodes.LRETURN || returnInsn.opcode == Opcodes.DRETURN) 2 else 1
}
}

View File

@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.state.GenerationState
@@ -12,12 +13,12 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.TYPEOF_NON_REIFIED_TYPE_PARAMETER_WITH_RECURSIVE_BOUND
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.TYPEOF_SUSPEND_TYPE
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.model.TypeParameterMarker
import org.jetbrains.org.objectweb.asm.Type
@@ -72,6 +73,14 @@ class PsiInlineIntrinsicsSupport(
override fun toKotlinType(type: KotlinType): KotlinType = type
override fun checkAnnotatedType(type: KotlinType) {
if (type.annotations.hasAnnotation(StandardNames.FqNames.extensionFunctionType)) {
state.diagnostics.report(TYPEOF_EXTENSION_FUNCTION_TYPE.on(reportErrorsOn))
} else if (type.annotations.any { it.fqName != JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION }) {
state.diagnostics.report(TYPEOF_ANNOTATED_TYPE.on(reportErrorsOn))
}
}
override fun reportSuspendTypeUnsupported() {
state.diagnostics.report(TYPEOF_SUSPEND_TYPE.on(reportErrorsOn))
}

View File

@@ -23,13 +23,11 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlin.resolve.jvm.annotations.isCallableMemberCompiledToJvmDefault
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
import org.jetbrains.kotlin.types.expressions.LabelResolver
import org.jetbrains.kotlin.utils.addIfNotNull

View File

@@ -75,6 +75,7 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
fun toKotlinType(type: KT): KotlinType
fun checkAnnotatedType(type: KT)
fun reportSuspendTypeUnsupported()
fun reportNonReifiedTypeParameterWithRecursiveBoundUnsupported(typeParameterName: Name)
}

View File

@@ -95,6 +95,8 @@ fun <KT : KotlinTypeMarker> TypeSystemCommonBackendContext.generateTypeOf(
intrinsicsSupport.reportSuspendTypeUnsupported()
}
intrinsicsSupport.checkAnnotatedType(type)
if (intrinsicsSupport.state.stableTypeOf) {
if (intrinsicsSupport.isMutableCollectionType(type)) {
v.invokestatic(REFLECTION, "mutableCollectionType", Type.getMethodDescriptor(K_TYPE, K_TYPE), false)

View File

@@ -17,11 +17,13 @@
package org.jetbrains.kotlin.codegen.optimization
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicVerifier
class MethodVerifier(private val checkPoint: String) : MethodTransformer() {
class MethodVerifier(private val checkPoint: String, private val generationState: GenerationState) : MethodTransformer() {
override fun transform(internalClassName: String, methodNode: MethodNode) {
if (!generationState.shouldValidateBytecode) return
try {
analyze(internalClassName, methodNode, BasicVerifier())
} catch (e: Throwable) {

View File

@@ -41,7 +41,7 @@ class OptimizationMethodVisitor(
val normalizationMethodTransformer = CompositeMethodTransformer(
FixStackWithLabelNormalizationMethodTransformer(),
MethodVerifier("AFTER mandatory stack transformations")
MethodVerifier("AFTER mandatory stack transformations", generationState)
)
val optimizationTransformer = CompositeMethodTransformer(
@@ -55,7 +55,7 @@ class OptimizationMethodVisitor(
DeadCodeEliminationMethodTransformer(),
RedundantGotoMethodTransformer(),
RedundantNopsCleanupMethodTransformer(),
MethodVerifier("AFTER optimizations")
MethodVerifier("AFTER optimizations", generationState)
)
override fun performTransformations(methodNode: MethodNode) {
@@ -73,24 +73,29 @@ class OptimizationMethodVisitor(
companion object {
private const val MEMORY_LIMIT_BY_METHOD_MB = 50
private const val TRY_CATCH_BLOCKS_LIMIT = 512
private const val TRY_CATCH_BLOCKS_SOFT_LIMIT = 16
fun canBeOptimized(node: MethodNode): Boolean {
if (node.tryCatchBlocks.size > TRY_CATCH_BLOCKS_LIMIT)
return false
val totalFramesSizeMb = node.instructions.size() * (node.maxLocals + node.maxStack) / (1024 * 1024)
return totalFramesSizeMb < MEMORY_LIMIT_BY_METHOD_MB
if (node.tryCatchBlocks.size > TRY_CATCH_BLOCKS_SOFT_LIMIT) {
if (getTotalFramesWeight(getTotalTcbSize(node), node) > MEMORY_LIMIT_BY_METHOD_MB)
return false
}
return getTotalFramesWeight(node.instructions.size(), node) < MEMORY_LIMIT_BY_METHOD_MB
}
fun canBeOptimizedUsingSourceInterpreter(node: MethodNode): Boolean {
if (node.tryCatchBlocks.size > TRY_CATCH_BLOCKS_LIMIT)
return false
val frameSize = node.maxLocals + node.maxStack
val methodSize = node.instructions.size().toLong()
val totalFramesSizeMb = methodSize * methodSize * frameSize / (1024 * 1024)
return totalFramesSizeMb < MEMORY_LIMIT_BY_METHOD_MB
val methodSize = node.instructions.size()
if (node.tryCatchBlocks.size > TRY_CATCH_BLOCKS_SOFT_LIMIT) {
if (getTotalFramesWeight(getTotalTcbSize(node) * methodSize, node) > MEMORY_LIMIT_BY_METHOD_MB)
return false
}
return getTotalFramesWeight(methodSize * methodSize, node) < MEMORY_LIMIT_BY_METHOD_MB
}
private fun getTotalFramesWeight(size: Int, node: MethodNode) =
size.toLong() * (node.maxLocals + node.maxStack) / (1024 * 1024)
private fun getTotalTcbSize(node: MethodNode) =
node.tryCatchBlocks.sumOf { node.instructions.indexOf(it.end) - node.instructions.indexOf(it.start) }
}
}

View File

@@ -56,7 +56,7 @@ class TaintedBoxedValue(private val boxedBasicValue: CleanBoxedValue) : BoxedBas
class BoxedValueDescriptor(
private val boxedType: Type,
boxedType: Type,
val boxingInsn: AbstractInsnNode,
val progressionIterator: ProgressionIteratorBasicValue?,
val generationState: GenerationState

View File

@@ -38,6 +38,10 @@ import java.util.*
class RedundantBoxingMethodTransformer(private val generationState: GenerationState) : MethodTransformer() {
override fun transform(internalClassName: String, node: MethodNode) {
val insns = node.instructions.toArray()
if (insns.none { it.isBoxing(generationState) || it.isMethodInsnWith(Opcodes.INVOKEINTERFACE) { name == "next" } })
return
val interpreter = RedundantBoxingInterpreter(node.instructions, generationState)
val frames = analyze(internalClassName, node, interpreter)

View File

@@ -33,7 +33,6 @@
package org.jetbrains.kotlin.codegen.optimization.common
import org.jetbrains.kotlin.codegen.inline.insnOpcodeText
import org.jetbrains.kotlin.codegen.inline.insnText
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.org.objectweb.asm.Opcodes
@@ -45,7 +44,7 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
import org.jetbrains.org.objectweb.asm.tree.analysis.Value
/**
* @see FlexibleMethodAnalyzer
* @see org.jetbrains.kotlin.codegen.optimization.fixStack.FastStackAnalyzer
*/
@Suppress("DuplicatedCode")
open class FastMethodAnalyzer<V : Value>(
@@ -56,34 +55,9 @@ open class FastMethodAnalyzer<V : Value>(
private val insnsArray = method.instructions.toArray()
private val nInsns = method.instructions.size()
// Single Predecessor Block (SPB) is a continuous sequence of instructions { I1, ... In } such that
// if I=insns[i] and J=insns[i+1] both belong to SPB,
// then I is a single immediate predecessor of J in a complete method control flow graph
// (including exception edges).
//
// Note that classic basic blocks are SPBs, but the opposite is not true:
// SPBs have single entry point, but can have multiple exit points
// (which lead to instructions not belonging to the given SPB).
// Example:
// aload 1
// dup
// ifnull LA
// invokevirtual foo()
// dup
// ifnull LB
// invokevirtual bar()
// goto LC
// is SPB (but not a basic block).
//
// For each J=insns[i+1] such that I=insns[i] belongs to the same SPB,
// data flow transfer function
// Execute( J, Merge( { Out(K) | K <- Pred(J) } ) )
// is effectively
// Execute( J, Out(I) ) )
// so, we don't need to merge frames for such I->J edges.
private val singlePredBlock = IntArray(nInsns)
private val isMergeNode = BooleanArray(nInsns)
val frames: Array<Frame<V>?> = arrayOfNulls(nInsns)
private val frames: Array<Frame<V>?> = arrayOfNulls(nInsns)
private val handlers: Array<MutableList<TryCatchBlockNode>?> = arrayOfNulls(nInsns)
private val queued = BooleanArray(nInsns)
@@ -97,14 +71,13 @@ open class FastMethodAnalyzer<V : Value>(
if (nInsns == 0) return frames
checkAssertions()
computeExceptionHandlersForEachInsn(method)
initSinglePredBlocks()
initMergeNodes()
val current = newFrame(method.maxLocals, method.maxStack)
val handler = newFrame(method.maxLocals, method.maxStack)
initControlFlowAnalysis(current, method, owner)
initLocals(current)
mergeControlFlowEdge(0, current)
while (top > 0) {
val insn = queue[--top]
@@ -117,16 +90,16 @@ open class FastMethodAnalyzer<V : Value>(
val insnType = insnNode.type
if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) {
visitNopInsn(f, insn)
mergeControlFlowEdge(insn + 1, f)
} else {
current.init(f).execute(insnNode, interpreter)
when {
insnNode is JumpInsnNode ->
visitJumpInsnNode(insnNode, current, insn, insnOpcode)
insnNode is LookupSwitchInsnNode ->
visitLookupSwitchInsnNode(insnNode, current, insn)
insnNode is TableSwitchInsnNode ->
visitTableSwitchInsnNode(insnNode, current, insn)
insnType == AbstractInsnNode.JUMP_INSN ->
visitJumpInsnNode(insnNode as JumpInsnNode, current, insn, insnOpcode)
insnType == AbstractInsnNode.LOOKUPSWITCH_INSN ->
visitLookupSwitchInsnNode(insnNode as LookupSwitchInsnNode, current)
insnType == AbstractInsnNode.TABLESWITCH_INSN ->
visitTableSwitchInsnNode(insnNode as TableSwitchInsnNode, current)
insnOpcode != Opcodes.ATHROW && (insnOpcode < Opcodes.IRETURN || insnOpcode > Opcodes.RETURN) ->
visitOpInsn(current, insn)
else -> {
@@ -141,7 +114,7 @@ open class FastMethodAnalyzer<V : Value>(
handler.init(f)
handler.clearStack()
handler.push(interpreter.newValue(exnType))
mergeControlFlowEdge(insn, jump, handler)
mergeControlFlowEdge(jump, handler)
}
} catch (e: AnalyzerException) {
@@ -155,87 +128,56 @@ open class FastMethodAnalyzer<V : Value>(
return frames
}
internal fun initLocals(current: Frame<V>) {
current.setReturn(interpreter.newValue(Type.getReturnType(method.desc)))
val args = Type.getArgumentTypes(method.desc)
var local = 0
if ((method.access and Opcodes.ACC_STATIC) == 0) {
val ctype = Type.getObjectType(owner)
current.setLocal(local++, interpreter.newValue(ctype))
}
for (arg in args) {
current.setLocal(local++, interpreter.newValue(arg))
if (arg.size == 2) {
current.setLocal(local++, interpreter.newValue(null))
}
}
while (local < method.maxLocals) {
current.setLocal(local++, interpreter.newValue(null))
}
}
private fun AbstractInsnNode.indexOf() =
method.instructions.indexOf(this)
private fun initSinglePredBlocks() {
markSinglePredBlockEntries()
markSinglePredBlockBodies()
}
private fun markSinglePredBlockEntries() {
// Method entry point is SPB entry point.
var blockId = 0
singlePredBlock[0] = ++blockId
// Every jump target is SPB entry point.
private fun initMergeNodes() {
for (insn in insnsArray) {
when (insn) {
is JumpInsnNode -> {
val labelIndex = insn.label.indexOf()
if (singlePredBlock[labelIndex] == 0) {
singlePredBlock[labelIndex] = ++blockId
when (insn.type) {
AbstractInsnNode.JUMP_INSN -> {
val jumpInsn = insn as JumpInsnNode
isMergeNode[jumpInsn.label.indexOf()] = true
}
AbstractInsnNode.LOOKUPSWITCH_INSN -> {
val switchInsn = insn as LookupSwitchInsnNode
isMergeNode[switchInsn.dflt.indexOf()] = true
for (label in switchInsn.labels) {
isMergeNode[label.indexOf()] = true
}
}
is LookupSwitchInsnNode -> {
insn.dflt?.let { dfltLabel ->
val dfltIndex = dfltLabel.indexOf()
if (singlePredBlock[dfltIndex] == 0) {
singlePredBlock[dfltIndex] = ++blockId
}
}
for (label in insn.labels) {
val labelIndex = label.indexOf()
if (singlePredBlock[labelIndex] == 0) {
singlePredBlock[labelIndex] = ++blockId
}
}
}
is TableSwitchInsnNode -> {
insn.dflt?.let { dfltLabel ->
val dfltIndex = dfltLabel.indexOf()
if (singlePredBlock[dfltIndex] == 0) {
singlePredBlock[dfltIndex] = ++blockId
}
}
for (label in insn.labels) {
val labelIndex = label.indexOf()
if (singlePredBlock[labelIndex] == 0) {
singlePredBlock[labelIndex] = ++blockId
}
AbstractInsnNode.TABLESWITCH_INSN -> {
val switchInsn = insn as TableSwitchInsnNode
isMergeNode[switchInsn.dflt.indexOf()] = true
for (label in switchInsn.labels) {
isMergeNode[label.indexOf()] = true
}
}
}
}
// Every try-catch block handler entry point is SPB entry point
for (tcb in method.tryCatchBlocks) {
val handlerIndex = tcb.handler.indexOf()
if (singlePredBlock[handlerIndex] == 0) {
singlePredBlock[handlerIndex] = ++blockId
}
isMergeNode[tcb.handler.indexOf()] = true
}
}
private fun markSinglePredBlockBodies() {
var current = 0
for ((i, insn) in insnsArray.withIndex()) {
if (singlePredBlock[i] == 0) {
singlePredBlock[i] = current
} else {
// Entered a new SPB.
current = singlePredBlock[i]
}
// GOTO, ATHROW, *RETURN instructions terminate current SPB.
when (insn.opcode) {
Opcodes.GOTO,
Opcodes.ATHROW,
in Opcodes.IRETURN..Opcodes.RETURN ->
current = 0
}
}
}
fun getFrame(insn: AbstractInsnNode): Frame<V>? =
frames[insn.indexOf()]
@@ -246,62 +188,33 @@ open class FastMethodAnalyzer<V : Value>(
}
private fun visitOpInsn(current: Frame<V>, insn: Int) {
mergeControlFlowEdge(insn, insn + 1, current)
mergeControlFlowEdge(insn + 1, current)
}
private fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: Frame<V>, insn: Int) {
var jump = insnNode.dflt.indexOf()
mergeControlFlowEdge(insn, jump, current)
private fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: Frame<V>) {
mergeControlFlowEdge(insnNode.dflt.indexOf(), current)
// In most cases order of visiting switch labels should not matter
// The only one is a tableswitch being added in the beginning of coroutine method, these switch' labels may lead
// in the middle of try/catch block, and FixStackAnalyzer is not ready for this (trying to restore stack before it was saved)
// So we just fix the order of labels being traversed: the first one should be one at the method beginning
// Using 'reversed' is because nodes are processed in LIFO order
for (label in insnNode.labels.reversed()) {
jump = label.indexOf()
mergeControlFlowEdge(insn, jump, current)
for (label in insnNode.labels.asReversed()) {
mergeControlFlowEdge(label.indexOf(), current)
}
}
private fun visitLookupSwitchInsnNode(insnNode: LookupSwitchInsnNode, current: Frame<V>, insn: Int) {
var jump = insnNode.dflt.indexOf()
mergeControlFlowEdge(insn, jump, current)
private fun visitLookupSwitchInsnNode(insnNode: LookupSwitchInsnNode, current: Frame<V>) {
mergeControlFlowEdge(insnNode.dflt.indexOf(), current)
for (label in insnNode.labels) {
jump = label.indexOf()
mergeControlFlowEdge(insn, jump, current)
mergeControlFlowEdge(label.indexOf(), current)
}
}
private fun visitJumpInsnNode(insnNode: JumpInsnNode, current: Frame<V>, insn: Int, insnOpcode: Int) {
if (insnOpcode != Opcodes.GOTO) {
mergeControlFlowEdge(insn, insn + 1, current)
mergeControlFlowEdge(insn + 1, current)
}
val jump = insnNode.label.indexOf()
mergeControlFlowEdge(insn, jump, current)
}
private fun visitNopInsn(f: Frame<V>, insn: Int) {
mergeControlFlowEdge(insn, insn + 1, f)
}
private fun initControlFlowAnalysis(current: Frame<V>, m: MethodNode, owner: String) {
current.setReturn(interpreter.newValue(Type.getReturnType(m.desc)))
val args = Type.getArgumentTypes(m.desc)
var local = 0
if ((m.access and Opcodes.ACC_STATIC) == 0) {
val ctype = Type.getObjectType(owner)
current.setLocal(local++, interpreter.newValue(ctype))
}
for (arg in args) {
current.setLocal(local++, interpreter.newValue(arg))
if (arg.size == 2) {
current.setLocal(local++, interpreter.newValue(null))
}
}
while (local < m.maxLocals) {
current.setLocal(local++, interpreter.newValue(null))
}
mergeControlFlowEdge(0, 0, current)
mergeControlFlowEdge(insnNode.label.indexOf(), current)
}
private fun computeExceptionHandlersForEachInsn(m: MethodNode) {
@@ -320,15 +233,14 @@ open class FastMethodAnalyzer<V : Value>(
}
}
private fun mergeControlFlowEdge(src: Int, dest: Int, frame: Frame<V>) {
private fun mergeControlFlowEdge(dest: Int, frame: Frame<V>) {
val oldFrame = frames[dest]
val changes = when {
oldFrame == null -> {
frames[dest] = newFrame(frame.locals, frame.maxStackSize).apply { init(frame) }
true
}
dest == src + 1 && singlePredBlock[src] == singlePredBlock[dest] -> {
// Forward jump within a single predecessor block, no need to merge.
!isMergeNode[dest] -> {
oldFrame.init(frame)
true
}
@@ -340,35 +252,4 @@ open class FastMethodAnalyzer<V : Value>(
queue[top++] = dest
}
}
@Suppress("unused")
private fun dumpBlocksInfo() {
fun LabelNode?.labelText() =
if (this != null) "L#${indexOf()}" else "L<null>"
println("===== ${method.name} ${method.signature} ======")
for ((i, insn) in insnsArray.withIndex()) {
val insnText = when (insn) {
is LabelNode ->
"L#$i"
is JumpInsnNode ->
"${insn.insnOpcodeText} ${insn.label.labelText()}"
is TableSwitchInsnNode ->
"${insn.insnOpcodeText} min=${insn.min} max=${insn.max} \n\t\t\t" +
"[${insn.labels.joinToString { it.labelText() }}] \n\t\t\t" +
"dflt:${insn.dflt.labelText()}"
is LookupSwitchInsnNode ->
"${insn.insnOpcodeText} \n\t\t\t" +
"[${insn.keys.zip(insn.labels).joinToString { (key, label) -> "$key: ${label.labelText()}"}}] \n\t\t\t" +
"dflt:${insn.dflt.labelText()}"
else ->
insn.insnText
}
println("$i\t${singlePredBlock[i]}\t$insnText")
}
for (tcb in method.tryCatchBlocks) {
println("\tTCB start:${tcb.start.labelText()} end:${tcb.end.labelText()} handler:${tcb.handler.labelText()}")
}
println()
}
}

View File

@@ -1,346 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package org.jetbrains.kotlin.codegen.optimization.common
import org.jetbrains.kotlin.codegen.inline.insnText
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
import org.jetbrains.org.objectweb.asm.tree.analysis.Value
/**
* This class is a modified version of `org.objectweb.asm.tree.analysis.Analyzer`
*
* @see FastMethodAnalyzer
*
* @author Eric Bruneton
* @author Dmitry Petrov
*/
@Suppress("DuplicatedCode")
open class FlexibleMethodAnalyzer<V : Value>(
private val owner: String,
val method: MethodNode,
protected val interpreter: Interpreter<V>
) {
protected val insnsArray: Array<AbstractInsnNode> = method.instructions.toArray()
private val nInsns = insnsArray.size
val frames: Array<Frame<V>?> = arrayOfNulls(nInsns)
private val handlers: Array<MutableList<TryCatchBlockNode>?> = arrayOfNulls(nInsns)
private val queued = BooleanArray(nInsns)
private val queue = IntArray(nInsns)
private var top = 0
private val singlePredBlock = IntArray(nInsns)
protected open fun newFrame(nLocals: Int, nStack: Int): Frame<V> = Frame(nLocals, nStack)
protected open fun visitControlFlowEdge(insn: Int, successor: Int): Boolean = true
protected open fun visitControlFlowExceptionEdge(insn: Int, successor: Int): Boolean = true
fun analyze(): Array<Frame<V>?> {
if (nInsns == 0) return frames
checkAssertions()
computeExceptionHandlersForEachInsn()
initSinglePredBlocks()
val current = newFrame(method.maxLocals, method.maxStack)
val handler = newFrame(method.maxLocals, method.maxStack)
initControlFlowAnalysis(current, method, owner)
while (top > 0) {
val insn = queue[--top]
val f = frames[insn]!!
queued[insn] = false
val insnNode = method.instructions[insn]
try {
val insnOpcode = insnNode.opcode
val insnType = insnNode.type
if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) {
visitNopInsn(f, insn)
} else {
current.init(f).execute(insnNode, interpreter)
when {
insnNode is JumpInsnNode ->
visitJumpInsnNode(insnNode, current, insn, insnOpcode)
insnNode is LookupSwitchInsnNode ->
visitLookupSwitchInsnNode(insnNode, current, insn)
insnNode is TableSwitchInsnNode ->
visitTableSwitchInsnNode(insnNode, current, insn)
insnOpcode != Opcodes.ATHROW && (insnOpcode < Opcodes.IRETURN || insnOpcode > Opcodes.RETURN) ->
visitOpInsn(current, insn)
else -> {
}
}
}
handlers[insn]?.forEach { tcb ->
val exnType = Type.getObjectType(tcb.type ?: "java/lang/Throwable")
val jump = tcb.handler.indexOf()
if (visitControlFlowExceptionEdge(insn, tcb.handler.indexOf())) {
handler.init(f)
handler.clearStack()
handler.push(interpreter.newValue(exnType))
mergeControlFlowEdge(insn, jump, handler)
}
}
} catch (e: AnalyzerException) {
throw AnalyzerException(e.node, "Error at instruction #$insn ${insnNode.insnText}: ${e.message}", e)
} catch (e: Exception) {
throw AnalyzerException(insnNode, "Error at instruction #$insn ${insnNode.insnText}: ${e.message}", e)
}
}
return frames
}
private fun initSinglePredBlocks() {
markSinglePredBlockEntries()
markSinglePredBlockBodies()
}
private fun markSinglePredBlockEntries() {
// Method entry point is SPB entry point.
var blockId = 0
singlePredBlock[0] = ++blockId
// Every jump target is SPB entry point.
for (insn in insnsArray) {
when (insn) {
is JumpInsnNode -> {
val labelIndex = insn.label.indexOf()
if (singlePredBlock[labelIndex] == 0) {
singlePredBlock[labelIndex] = ++blockId
}
}
is LookupSwitchInsnNode -> {
insn.dflt?.let { dfltLabel ->
val dfltIndex = dfltLabel.indexOf()
if (singlePredBlock[dfltIndex] == 0) {
singlePredBlock[dfltIndex] = ++blockId
}
}
for (label in insn.labels) {
val labelIndex = label.indexOf()
if (singlePredBlock[labelIndex] == 0) {
singlePredBlock[labelIndex] = ++blockId
}
}
}
is TableSwitchInsnNode -> {
insn.dflt?.let { dfltLabel ->
val dfltIndex = dfltLabel.indexOf()
if (singlePredBlock[dfltIndex] == 0) {
singlePredBlock[dfltIndex] = ++blockId
}
}
for (label in insn.labels) {
val labelIndex = label.indexOf()
if (singlePredBlock[labelIndex] == 0) {
singlePredBlock[labelIndex] = ++blockId
}
}
}
}
}
// Every try-catch block handler entry point is SPB entry point
for (tcb in method.tryCatchBlocks) {
val handlerIndex = tcb.handler.indexOf()
if (singlePredBlock[handlerIndex] == 0) {
singlePredBlock[handlerIndex] = ++blockId
}
}
}
private fun markSinglePredBlockBodies() {
var current = 0
for ((i, insn) in insnsArray.withIndex()) {
if (singlePredBlock[i] == 0) {
singlePredBlock[i] = current
} else {
// Entered a new SPB.
current = singlePredBlock[i]
}
// GOTO, ATHROW, *RETURN instructions terminate current SPB.
when (insn.opcode) {
Opcodes.GOTO,
Opcodes.ATHROW,
in Opcodes.IRETURN..Opcodes.RETURN ->
current = 0
}
}
}
private fun AbstractInsnNode.indexOf() = method.instructions.indexOf(this)
fun getFrame(insn: AbstractInsnNode): Frame<V>? =
frames[insn.indexOf()]
private fun checkAssertions() {
if (insnsArray.any { it.opcode == Opcodes.JSR || it.opcode == Opcodes.RET })
throw AssertionError("Subroutines are deprecated since Java 6")
}
private fun visitOpInsn(current: Frame<V>, insn: Int) {
processControlFlowEdge(current, insn, insn + 1)
}
private fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: Frame<V>, insn: Int) {
var jump = insnNode.dflt.indexOf()
processControlFlowEdge(current, insn, jump)
// In most cases order of visiting switch labels should not matter
// The only one is a tableswitch being added in the beginning of coroutine method, these switch' labels may lead
// in the middle of try/catch block, and FixStackAnalyzer is not ready for this (trying to restore stack before it was saved)
// So we just fix the order of labels being traversed: the first one should be one at the method beginning
// Using 'reversed' is because nodes are processed in LIFO order
for (label in insnNode.labels.reversed()) {
jump = label.indexOf()
processControlFlowEdge(current, insn, jump)
}
}
private fun visitLookupSwitchInsnNode(insnNode: LookupSwitchInsnNode, current: Frame<V>, insn: Int) {
var jump = insnNode.dflt.indexOf()
processControlFlowEdge(current, insn, jump)
for (label in insnNode.labels) {
jump = label.indexOf()
processControlFlowEdge(current, insn, jump)
}
}
private fun visitJumpInsnNode(insnNode: JumpInsnNode, current: Frame<V>, insn: Int, insnOpcode: Int) {
if (insnOpcode != Opcodes.GOTO && insnOpcode != Opcodes.JSR) {
processControlFlowEdge(current, insn, insn + 1)
}
val jump = insnNode.label.indexOf()
processControlFlowEdge(current, insn, jump)
}
private fun visitNopInsn(f: Frame<V>, insn: Int) {
processControlFlowEdge(f, insn, insn + 1)
}
private fun processControlFlowEdge(current: Frame<V>, insn: Int, jump: Int) {
if (visitControlFlowEdge(insn, jump)) {
mergeControlFlowEdge(insn, jump, current)
}
}
private fun initControlFlowAnalysis(current: Frame<V>, m: MethodNode, owner: String) {
current.setReturn(interpreter.newValue(Type.getReturnType(m.desc)))
val args = Type.getArgumentTypes(m.desc)
var local = 0
if ((m.access and Opcodes.ACC_STATIC) == 0) {
val ctype = Type.getObjectType(owner)
current.setLocal(local++, interpreter.newValue(ctype))
}
for (arg in args) {
current.setLocal(local++, interpreter.newValue(arg))
if (arg.size == 2) {
current.setLocal(local++, interpreter.newValue(null))
}
}
while (local < m.maxLocals) {
current.setLocal(local++, interpreter.newValue(null))
}
mergeControlFlowEdge(0, 0, current)
}
private fun computeExceptionHandlersForEachInsn() {
for (tcb in method.tryCatchBlocks) {
val begin = tcb.start.indexOf()
val end = tcb.end.indexOf()
for (j in begin until end) {
val insn = insnsArray[j]
if (!insn.isMeaningful) continue
var insnHandlers: MutableList<TryCatchBlockNode>? = handlers[j]
if (insnHandlers == null) {
insnHandlers = ArrayList<TryCatchBlockNode>()
handlers[j] = insnHandlers
}
insnHandlers.add(tcb)
}
}
}
private fun mergeControlFlowEdge(src: Int, dest: Int, frame: Frame<V>) {
val oldFrame = frames[dest]
val changes = when {
oldFrame == null -> {
frames[dest] = newFrame(frame.locals, frame.maxStackSize).apply { init(frame) }
true
}
dest == src + 1 && singlePredBlock[src] == singlePredBlock[dest] -> {
// Forward jump within a single predecessor block, no need to merge.
oldFrame.init(frame)
true
}
else ->
oldFrame.merge(frame, interpreter)
}
if (changes && !queued[dest]) {
queued[dest] = true
queue[top++] = dest
}
}
}

View File

@@ -0,0 +1,239 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jetbrains.kotlin.codegen.optimization.fixStack
import org.jetbrains.kotlin.codegen.inline.insnText
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
import org.jetbrains.org.objectweb.asm.tree.analysis.Value
/**
* @see org.jetbrains.kotlin.codegen.optimization.common.FastMethodAnalyzer
*/
@Suppress("DuplicatedCode")
internal open class FastStackAnalyzer<V : Value>(
private val owner: String,
val method: MethodNode,
protected val interpreter: Interpreter<V>
) {
protected val insnsArray: Array<AbstractInsnNode> = method.instructions.toArray()
private val nInsns = insnsArray.size
private val frames: Array<Frame<V>?> = arrayOfNulls(nInsns)
private val handlers: Array<MutableList<TryCatchBlockNode>?> = arrayOfNulls(nInsns)
private val queued = BooleanArray(nInsns)
private val queue = IntArray(nInsns)
private var top = 0
protected open fun newFrame(nLocals: Int, nStack: Int): Frame<V> = Frame(nLocals, nStack)
protected open fun visitControlFlowEdge(insn: Int, successor: Int): Boolean = true
protected open fun visitControlFlowExceptionEdge(insn: Int, successor: Int): Boolean = true
fun analyze(): Array<Frame<V>?> {
if (nInsns == 0) return frames
// This is a very specific version of method bytecode analyzer that doesn't perform any DFA,
// but infers stack types for reachable instructions instead.
checkAssertions()
computeExceptionEdges()
val current = newFrame(method.maxLocals, method.maxStack)
val handler = newFrame(method.maxLocals, method.maxStack)
initControlFlowAnalysis(current, method, owner)
while (top > 0) {
val insn = queue[--top]
val f = frames[insn]!!
queued[insn] = false
val insnNode = method.instructions[insn]
val insnOpcode = insnNode.opcode
val insnType = insnNode.type
try {
if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) {
visitNopInsn(f, insn)
} else {
current.init(f)
if (insnOpcode != Opcodes.RETURN) {
// Don't care about possibly incompatible return type
current.execute(insnNode, interpreter)
}
when {
insnType == AbstractInsnNode.JUMP_INSN ->
visitJumpInsnNode(insnNode as JumpInsnNode, current, insn, insnOpcode)
insnType == AbstractInsnNode.LOOKUPSWITCH_INSN ->
visitLookupSwitchInsnNode(insnNode as LookupSwitchInsnNode, current, insn)
insnType == AbstractInsnNode.TABLESWITCH_INSN ->
visitTableSwitchInsnNode(insnNode as TableSwitchInsnNode, current, insn)
insnOpcode != Opcodes.ATHROW && (insnOpcode < Opcodes.IRETURN || insnOpcode > Opcodes.RETURN) ->
visitOpInsn(current, insn)
else -> {
}
}
}
handlers[insn]?.forEach { tcb ->
val exnType = Type.getObjectType(tcb.type ?: "java/lang/Throwable")
val jump = tcb.handler.indexOf()
if (visitControlFlowExceptionEdge(insn, tcb.handler.indexOf())) {
handler.init(f)
handler.clearStack()
handler.push(interpreter.newValue(exnType))
mergeControlFlowEdge(jump, handler)
}
}
} catch (e: AnalyzerException) {
throw AnalyzerException(e.node, "Error at instruction #$insn ${insnNode.insnText}: ${e.message}", e)
} catch (e: Exception) {
throw AnalyzerException(insnNode, "Error at instruction #$insn ${insnNode.insnText}: ${e.message}", e)
}
}
return frames
}
private fun AbstractInsnNode.indexOf() = method.instructions.indexOf(this)
fun getFrame(insn: AbstractInsnNode): Frame<V>? =
frames[insn.indexOf()]
private fun checkAssertions() {
if (insnsArray.any { it.opcode == Opcodes.JSR || it.opcode == Opcodes.RET })
throw AssertionError("Subroutines are deprecated since Java 6")
}
private fun visitOpInsn(current: Frame<V>, insn: Int) {
processControlFlowEdge(current, insn, insn + 1)
}
private fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: Frame<V>, insn: Int) {
var jump = insnNode.dflt.indexOf()
processControlFlowEdge(current, insn, jump)
// In most cases order of visiting switch labels should not matter
// The only one is a tableswitch being added in the beginning of coroutine method, these switch' labels may lead
// in the middle of try/catch block, and FixStackAnalyzer is not ready for this (trying to restore stack before it was saved)
// So we just fix the order of labels being traversed: the first one should be one at the method beginning
// Using 'reversed' is because nodes are processed in LIFO order
for (label in insnNode.labels.reversed()) {
jump = label.indexOf()
processControlFlowEdge(current, insn, jump)
}
}
private fun visitLookupSwitchInsnNode(insnNode: LookupSwitchInsnNode, current: Frame<V>, insn: Int) {
var jump = insnNode.dflt.indexOf()
processControlFlowEdge(current, insn, jump)
for (label in insnNode.labels) {
jump = label.indexOf()
processControlFlowEdge(current, insn, jump)
}
}
private fun visitJumpInsnNode(insnNode: JumpInsnNode, current: Frame<V>, insn: Int, insnOpcode: Int) {
if (insnOpcode != Opcodes.GOTO) {
processControlFlowEdge(current, insn, insn + 1)
}
val jump = insnNode.label.indexOf()
processControlFlowEdge(current, insn, jump)
}
private fun visitNopInsn(f: Frame<V>, insn: Int) {
processControlFlowEdge(f, insn, insn + 1)
}
private fun processControlFlowEdge(current: Frame<V>, insn: Int, jump: Int) {
if (visitControlFlowEdge(insn, jump)) {
mergeControlFlowEdge(jump, current)
}
}
private fun initControlFlowAnalysis(current: Frame<V>, m: MethodNode, owner: String) {
current.setReturn(interpreter.newValue(Type.getReturnType(m.desc)))
val args = Type.getArgumentTypes(m.desc)
var local = 0
if ((m.access and Opcodes.ACC_STATIC) == 0) {
val ctype = Type.getObjectType(owner)
current.setLocal(local++, interpreter.newValue(ctype))
}
for (arg in args) {
current.setLocal(local++, interpreter.newValue(arg))
if (arg.size == 2) {
current.setLocal(local++, interpreter.newValue(null))
}
}
while (local < m.maxLocals) {
current.setLocal(local++, interpreter.newValue(null))
}
mergeControlFlowEdge(0, current)
}
private fun computeExceptionEdges() {
for (tcb in method.tryCatchBlocks) {
// Don't have to visit same exception handler multiple times - we care only about stack state at TCB start.
val start = tcb.start.indexOf()
var insnHandlers: MutableList<TryCatchBlockNode>? = handlers[start]
if (insnHandlers == null) {
insnHandlers = ArrayList()
handlers[start] = insnHandlers
}
insnHandlers.add(tcb)
}
}
private fun mergeControlFlowEdge(dest: Int, frame: Frame<V>) {
val destFrame = frames[dest]
if (destFrame == null) {
// Don't have to visit same instruction multiple times - we care only about "initial" stack state.
frames[dest] = newFrame(frame.locals, frame.maxStackSize).apply { init(frame) }
if (!queued[dest]) {
queued[dest] = true
queue[top++] = dest
}
}
}
}

View File

@@ -19,9 +19,6 @@ package org.jetbrains.kotlin.codegen.optimization.fixStack
import com.intellij.util.containers.Stack
import org.jetbrains.kotlin.codegen.inline.isAfterInlineMarker
import org.jetbrains.kotlin.codegen.inline.isBeforeInlineMarker
import org.jetbrains.kotlin.codegen.inline.isMarkedReturn
import org.jetbrains.kotlin.codegen.optimization.common.FlexibleMethodAnalyzer
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.org.objectweb.asm.Opcodes
@@ -29,8 +26,6 @@ import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode
import org.jetbrains.org.objectweb.asm.tree.LabelNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException
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
import kotlin.math.max
@@ -50,9 +45,14 @@ internal class FixStackAnalyzer(
val maxExtraStackSize: Int get() = analyzer.maxExtraStackSize
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 getStackToSpill(location: AbstractInsnNode): List<FixStackValue>? =
analyzer.spilledStacks[location]
fun getActualStack(location: AbstractInsnNode): List<FixStackValue>? =
getFrame(location)?.getStackContent()
fun getActualStackSize(location: AbstractInsnNode): Int =
getFrame(location)?.stackSizeWithExtra ?: DEAD_CODE_STACK_SIZE
fun getExpectedStackSize(location: AbstractInsnNode): Int {
// We should look for expected stack size at loop entry point markers if available,
@@ -90,9 +90,9 @@ internal class FixStackAnalyzer(
private val analyzer = InternalAnalyzer(owner)
private inner class InternalAnalyzer(owner: String) :
FlexibleMethodAnalyzer<BasicValue>(owner, method, OptimizationBasicInterpreter()) {
FastStackAnalyzer<FixStackValue>(owner, method, FixStackInterpreter()) {
val spilledStacks = hashMapOf<AbstractInsnNode, List<BasicValue>>()
val spilledStacks = hashMapOf<AbstractInsnNode, List<FixStackValue>>()
var maxExtraStackSize = 0; private set
override fun visitControlFlowEdge(insn: Int, successor: Int): Boolean {
@@ -101,15 +101,15 @@ internal class FixStackAnalyzer(
return !(insnNode is JumpInsnNode && context.breakContinueGotoNodes.contains(insnNode))
}
override fun newFrame(nLocals: Int, nStack: Int): Frame<BasicValue> =
override fun newFrame(nLocals: Int, nStack: Int): Frame<FixStackValue> =
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>()
inner class FixStackFrame(nLocals: Int, nStack: Int) : Frame<FixStackValue>(nLocals, nStack) {
val extraStack = Stack<FixStackValue>()
override fun init(src: Frame<out BasicValue>): Frame<BasicValue> {
override fun init(src: Frame<out FixStackValue>): Frame<FixStackValue> {
extraStack.clear()
extraStack.addAll((src as FixStackFrame).extraStack)
return super.init(src)
@@ -120,7 +120,7 @@ internal class FixStackAnalyzer(
super.clearStack()
}
override fun execute(insn: AbstractInsnNode, interpreter: Interpreter<BasicValue>) {
override fun execute(insn: AbstractInsnNode, interpreter: Interpreter<FixStackValue>) {
when {
PseudoInsn.SAVE_STACK_BEFORE_TRY.isa(insn) ->
executeSaveStackBeforeTry(insn)
@@ -130,10 +130,8 @@ internal class FixStackAnalyzer(
executeBeforeInlineCallMarker(insn)
isAfterInlineMarker(insn) ->
executeAfterInlineCallMarker(insn)
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
}
insn.opcode == Opcodes.RETURN ->
return
}
super.execute(insn, interpreter)
@@ -141,14 +139,16 @@ internal class FixStackAnalyzer(
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) }
fun getStackContent(): List<FixStackValue> {
val savedStack = ArrayList<FixStackValue>()
for (i in 0 until super.getStackSize()) {
savedStack.add(super.getStack(i))
}
savedStack.addAll(extraStack)
return savedStack
}
override fun push(value: BasicValue) {
override fun push(value: FixStackValue) {
if (super.getStackSize() < maxStackSize) {
super.push(value)
} else {
@@ -157,19 +157,18 @@ internal class FixStackAnalyzer(
}
}
fun pushAll(values: Collection<BasicValue>) {
fun pushAll(values: Collection<FixStackValue>) {
values.forEach { push(it) }
}
override fun pop(): BasicValue {
return if (extraStack.isNotEmpty()) {
override fun pop(): FixStackValue =
if (extraStack.isNotEmpty()) {
extraStack.pop()
} else {
super.pop()
}
}
override fun setStack(i: Int, value: BasicValue) {
override fun setStack(i: Int, value: FixStackValue) {
if (i < super.getMaxStackSize()) {
super.setStack(i, value)
} else {
@@ -177,29 +176,8 @@ internal class FixStackAnalyzer(
}
}
override fun merge(frame: Frame<out BasicValue>, interpreter: Interpreter<BasicValue>): Boolean {
val other = frame as FixStackFrame
if (stackSizeWithExtra != other.stackSizeWithExtra) {
throw AnalyzerException(null, "Incompatible stack heights")
}
var changed = false
for (i in 0 until stackSize) {
val v0 = super.getStack(i)
val vm = interpreter.merge(v0, other.getStack(i))
if (vm != v0) {
super.setStack(i, vm)
changed = true
}
}
for (i in 0 until extraStack.size) {
val v0 = extraStack[i]
val vm = interpreter.merge(v0, other.extraStack[i])
if (vm != v0) {
extraStack[i] = vm
changed = true
}
}
return changed
override fun merge(frame: Frame<out FixStackValue>, interpreter: Interpreter<FixStackValue>): Boolean {
throw UnsupportedOperationException("Stack normalization should not merge frames")
}
}

View File

@@ -0,0 +1,157 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.optimization.fixStack
import org.jetbrains.kotlin.codegen.inline.insnOpcodeText
import org.jetbrains.org.objectweb.asm.Handle
import org.jetbrains.org.objectweb.asm.Opcodes.*
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
open class FixStackInterpreter : Interpreter<FixStackValue>(API_VERSION) {
override fun newValue(type: Type?): FixStackValue =
type?.toFixStackValue()
?: FixStackValue.UNINITIALIZED
override fun newOperation(insn: AbstractInsnNode): FixStackValue? =
when (insn.opcode) {
ACONST_NULL ->
FixStackValue.OBJECT
ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5 ->
FixStackValue.INT
LCONST_0, LCONST_1 ->
FixStackValue.LONG
FCONST_0, FCONST_1, FCONST_2 ->
FixStackValue.FLOAT
DCONST_0, DCONST_1 ->
FixStackValue.DOUBLE
BIPUSH, SIPUSH ->
FixStackValue.INT
LDC -> {
when (val cst = (insn as LdcInsnNode).cst) {
is Int ->
FixStackValue.INT
is Float ->
FixStackValue.FLOAT
is Long ->
FixStackValue.LONG
is Double ->
FixStackValue.DOUBLE
is String, is Handle ->
FixStackValue.OBJECT
is Type -> {
val sort = cst.sort
if (sort == Type.OBJECT || sort == Type.ARRAY || sort == Type.METHOD)
FixStackValue.OBJECT
else
throw IllegalArgumentException("Illegal LDC constant $cst")
}
else ->
throw IllegalArgumentException("Illegal LDC constant $cst")
}
}
GETSTATIC ->
newValue(Type.getType((insn as FieldInsnNode).desc))
NEW ->
newValue(Type.getObjectType((insn as TypeInsnNode).desc))
else ->
throw IllegalArgumentException("Unexpected instruction: " + insn.insnOpcodeText)
}
override fun copyOperation(insn: AbstractInsnNode, value: FixStackValue?): FixStackValue =
when (insn.opcode) {
ILOAD -> FixStackValue.INT
LLOAD -> FixStackValue.LONG
FLOAD -> FixStackValue.FLOAT
DLOAD -> FixStackValue.DOUBLE
ALOAD -> FixStackValue.OBJECT
else -> value!!
}
override fun binaryOperation(insn: AbstractInsnNode, value1: FixStackValue?, value2: FixStackValue?): FixStackValue? =
when (insn.opcode) {
IALOAD, BALOAD, CALOAD, SALOAD, IADD, ISUB, IMUL, IDIV, IREM, ISHL, ISHR, IUSHR, IAND, IOR, IXOR ->
FixStackValue.INT
FALOAD, FADD, FSUB, FMUL, FDIV, FREM ->
FixStackValue.FLOAT
LALOAD, LADD, LSUB, LMUL, LDIV, LREM, LSHL, LSHR, LUSHR, LAND, LOR, LXOR ->
FixStackValue.LONG
DALOAD, DADD, DSUB, DMUL, DDIV, DREM ->
FixStackValue.DOUBLE
AALOAD ->
FixStackValue.OBJECT
LCMP, FCMPL, FCMPG, DCMPL, DCMPG ->
FixStackValue.INT
IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, PUTFIELD ->
null
else ->
throw IllegalArgumentException("Unexpected instruction: " + insn.insnOpcodeText)
}
override fun ternaryOperation(
insn: AbstractInsnNode,
value1: FixStackValue?,
value2: FixStackValue?,
value3: FixStackValue?
): FixStackValue? =
null
override fun naryOperation(insn: AbstractInsnNode, values: List<FixStackValue?>): FixStackValue? =
when (insn.opcode) {
MULTIANEWARRAY ->
newValue(Type.getType((insn as MultiANewArrayInsnNode).desc))
INVOKEDYNAMIC ->
newValue(Type.getReturnType((insn as InvokeDynamicInsnNode).desc))
else ->
newValue(Type.getReturnType((insn as MethodInsnNode).desc))
}
override fun returnOperation(insn: AbstractInsnNode?, value: FixStackValue?, expected: FixStackValue?) {
}
override fun unaryOperation(insn: AbstractInsnNode, value: FixStackValue?): FixStackValue? =
when (insn.opcode) {
INEG, IINC, L2I, F2I, D2I, I2B, I2C, I2S ->
FixStackValue.INT
FNEG, I2F, L2F, D2F ->
FixStackValue.FLOAT
LNEG, I2L, F2L, D2L ->
FixStackValue.LONG
DNEG, I2D, L2D, F2D ->
FixStackValue.DOUBLE
IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN, PUTSTATIC ->
null
GETFIELD ->
newValue(Type.getType((insn as FieldInsnNode).desc))
NEWARRAY ->
FixStackValue.OBJECT
ANEWARRAY -> {
FixStackValue.OBJECT
}
ARRAYLENGTH ->
FixStackValue.INT
ATHROW ->
null
CHECKCAST ->
FixStackValue.OBJECT
INSTANCEOF ->
FixStackValue.INT
MONITORENTER, MONITOREXIT, IFNULL, IFNONNULL ->
null
else ->
throw IllegalArgumentException("Unexpected instruction: " + insn.insnOpcodeText)
}
override fun merge(v: FixStackValue?, w: FixStackValue?): FixStackValue? =
when {
v == w -> v
v == null -> w
w == null -> v
else -> throw AssertionError("Mismatching value kinds: $v != $w")
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.optimization.fixStack
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.analysis.Value
enum class FixStackValue(
private val _size: Int,
val loadOpcode: Int,
val storeOpcode: Int,
val popOpcode: Int
) : Value {
INT(1, Opcodes.ILOAD, Opcodes.ISTORE, Opcodes.POP),
LONG(2, Opcodes.LLOAD, Opcodes.LSTORE, Opcodes.POP2),
FLOAT(1, Opcodes.FLOAD, Opcodes.FSTORE, Opcodes.POP),
DOUBLE(2, Opcodes.DLOAD, Opcodes.DSTORE, Opcodes.POP2),
OBJECT(1, Opcodes.ALOAD, Opcodes.ASTORE, Opcodes.POP),
UNINITIALIZED(1, -1, -1, -1)
;
override fun getSize(): Int = _size
}
fun Type.toFixStackValue(): FixStackValue? =
when (this.sort) {
Type.VOID -> null
Type.BOOLEAN, Type.BYTE, Type.CHAR, Type.SHORT, Type.INT -> FixStackValue.INT
Type.LONG -> FixStackValue.LONG
Type.FLOAT -> FixStackValue.FLOAT
Type.DOUBLE -> FixStackValue.DOUBLE
Type.OBJECT, Type.ARRAY, Type.METHOD -> FixStackValue.OBJECT
else -> throw AssertionError("Unexpected type: $this")
}

View File

@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.codegen.optimization.fixStack
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
import kotlin.math.max
internal class LocalVariablesManager(val context: FixStackContext, val methodNode: MethodNode) {
@@ -39,7 +38,10 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod
methodNode.maxLocals = max(methodNode.maxLocals, newValue)
}
fun allocateVariablesForSaveStackMarker(saveStackMarker: AbstractInsnNode, savedStackValues: List<BasicValue>): SavedStackDescriptor {
fun allocateVariablesForSaveStackMarker(
saveStackMarker: AbstractInsnNode,
savedStackValues: List<FixStackValue>
): SavedStackDescriptor {
val numRestoreStackMarkers = context.restoreStackMarkersForSaveMarker[saveStackMarker]!!.size
return allocateNewHandle(numRestoreStackMarkers, saveStackMarker, savedStackValues)
}
@@ -47,10 +49,10 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod
private fun allocateNewHandle(
numRestoreStackMarkers: Int,
saveStackMarker: AbstractInsnNode,
savedStackValues: List<BasicValue>
savedStackValues: List<FixStackValue>
): SavedStackDescriptor {
if (savedStackValues.any { it.type == null }) {
throw AssertionError("Uninitialized value on stack at ${methodNode.instructions.indexOf(saveStackMarker)}")
if (savedStackValues.any { it == FixStackValue.UNINITIALIZED }) {
throw AssertionError("Uninitialized value on stack at ${methodNode.instructions.indexOf(saveStackMarker)}: $savedStackValues")
}
val firstUnusedLocalVarIndex = getFirstUnusedLocalVariableIndex()
@@ -78,7 +80,7 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod
fun allocateVariablesForBeforeInlineMarker(
beforeInlineMarker: AbstractInsnNode,
savedStackValues: List<BasicValue>
savedStackValues: List<FixStackValue>
): SavedStackDescriptor {
return allocateNewHandle(1, beforeInlineMarker, savedStackValues)
}
@@ -101,7 +103,7 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod
}
}
fun createReturnValueVariable(returnValue: BasicValue): Int {
fun createReturnValueVariable(returnValue: FixStackValue): Int {
val returnValueIndex = getFirstUnusedLocalVariableIndex()
updateMaxLocals(returnValueIndex + returnValue.size)
return returnValueIndex

View File

@@ -54,10 +54,10 @@ fun <V : Value> Frame<V>.peekWords(size1: Int, size2: Int): List<V>? {
}
class SavedStackDescriptor(
val savedValues: List<BasicValue>,
val savedValues: List<FixStackValue>,
val firstLocalVarIndex: Int
) {
private val savedValuesSize = savedValues.fold(0, { size, value -> size + value.size })
private val savedValuesSize = savedValues.fold(0) { size, value -> size + value.size }
val firstUnusedLocalVarIndex = firstLocalVarIndex + savedValuesSize
override fun toString(): String =
@@ -88,13 +88,13 @@ fun restoreStackWithReturnValue(
methodNode: MethodNode,
nodeToReplace: AbstractInsnNode,
savedStackDescriptor: SavedStackDescriptor,
returnValue: BasicValue,
returnValue: FixStackValue,
returnValueLocalVarIndex: Int
) {
with(methodNode.instructions) {
insertBefore(nodeToReplace, VarInsnNode(returnValue.type.getOpcode(Opcodes.ISTORE), returnValueLocalVarIndex))
insertBefore(nodeToReplace, VarInsnNode(returnValue.storeOpcode, returnValueLocalVarIndex))
generateLoadInstructions(methodNode, nodeToReplace, savedStackDescriptor)
insertBefore(nodeToReplace, VarInsnNode(returnValue.type.getOpcode(Opcodes.ILOAD), returnValueLocalVarIndex))
insertBefore(nodeToReplace, VarInsnNode(returnValue.loadOpcode, returnValueLocalVarIndex))
remove(nodeToReplace)
}
}
@@ -102,10 +102,7 @@ fun restoreStackWithReturnValue(
fun generateLoadInstructions(methodNode: MethodNode, location: AbstractInsnNode, savedStackDescriptor: SavedStackDescriptor) {
var localVarIndex = savedStackDescriptor.firstLocalVarIndex
for (value in savedStackDescriptor.savedValues) {
methodNode.instructions.insertBefore(
location,
VarInsnNode(value.type.getOpcode(Opcodes.ILOAD), localVarIndex)
)
methodNode.instructions.insertBefore(location, VarInsnNode(value.loadOpcode, localVarIndex))
localVarIndex += value.size
}
}
@@ -114,10 +111,7 @@ fun generateStoreInstructions(methodNode: MethodNode, location: AbstractInsnNode
var localVarIndex = savedStackDescriptor.firstUnusedLocalVarIndex
for (value in savedStackDescriptor.savedValues.asReversed()) {
localVarIndex -= value.size
methodNode.instructions.insertBefore(
location,
VarInsnNode(value.type.getOpcode(Opcodes.ISTORE), localVarIndex)
)
methodNode.instructions.insertBefore(location, VarInsnNode(value.storeOpcode, localVarIndex))
}
}
@@ -146,10 +140,10 @@ 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, stackContent: List<FixStackValue>) {
with(methodNode.instructions) {
for (stackValue in stackContent.subList(expectedStackSize, stackContent.size)) {
insert(node, getPopInstruction(stackValue))
insert(node, InsnNode(stackValue.popOpcode))
}
remove(node)
}

View File

@@ -299,6 +299,8 @@ class GenerationState private constructor(
!configuration.getBoolean(JVMConfigurationKeys.NO_UNIFIED_NULL_CHECKS)
val functionsWithInlineClassReturnTypesMangled: Boolean =
languageVersionSettings.supportsFeature(LanguageFeature.MangleClassMembersReturningInlineClasses)
val shouldValidateIr = configuration.getBoolean(JVMConfigurationKeys.VALIDATE_IR)
val shouldValidateBytecode = configuration.getBoolean(JVMConfigurationKeys.VALIDATE_BYTECODE)
val rootContext: CodegenContext<*> = RootContext(this)
@@ -405,8 +407,8 @@ class GenerationState private constructor(
this[KOTLIN_1_2] = oldMetadataVersion
this[KOTLIN_1_3] = oldMetadataVersion
this[KOTLIN_1_4] = JvmMetadataVersion(1, 4, 3)
this[KOTLIN_1_5] = JvmMetadataVersion.INSTANCE
this[KOTLIN_1_6] = JvmMetadataVersion(1, 6, 0)
this[KOTLIN_1_5] = JvmMetadataVersion(1, 5, 1)
this[KOTLIN_1_6] = JvmMetadataVersion.INSTANCE
this[KOTLIN_1_7] = JvmMetadataVersion(1, 7, 0)
check(size == LanguageVersion.values().size) {

View File

@@ -12,25 +12,6 @@ val otherCompilerModules = compilerModules.filter { it != path }
val tasksWithWarnings: List<String> by rootProject.extra
val effectSystemEnabled: Boolean by rootProject.extra
val newInferenceEnabled: Boolean by rootProject.extra
configureFreeCompilerArg(effectSystemEnabled, "-Xeffect-system")
configureFreeCompilerArg(newInferenceEnabled, "-Xnew-inference")
configureFreeCompilerArg(true, "-Xuse-mixed-named-arguments")
fun configureFreeCompilerArg(isEnabled: Boolean, compilerArgument: String) {
if (isEnabled) {
allprojects {
tasks.withType<KotlinCompile<*>> {
kotlinOptions {
freeCompilerArgs += listOf(compilerArgument)
}
}
}
}
}
val antLauncherJar by configurations.creating
dependencies {
@@ -85,7 +66,9 @@ if (kotlinBuildProperties.isInJpsBuildIdeaSync) {
idea {
this.module.generatedSourceDirs.add(generationRoot)
}
} else if (!kotlinBuildProperties.useFir && !kotlinBuildProperties.disableWerror) {
}
if (!kotlinBuildProperties.disableWerror) {
allprojects {
tasks.withType<KotlinCompile<*>> {
if (path !in tasksWithWarnings) {

View File

@@ -57,10 +57,10 @@ sourceSets {
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
kotlinOptions {
languageVersion = "1.3"
apiVersion = "1.3"
languageVersion = "1.4"
apiVersion = "1.4"
freeCompilerArgs = freeCompilerArgs - "-progressive" + listOf(
"-Xskip-prerelease-check", "-Xsuppress-version-warnings"
"-Xskip-prerelease-check", "-Xsuppress-version-warnings", "-Xuse-mixed-named-arguments", "-Xnew-inference"
)
}
}

View File

@@ -1,12 +0,0 @@
<idea-plugin>
<id>org.jetbrains.kotlin</id>
<version>1.2</version>
<!-- Don't add more extension points here! Logic in KotlinCoreEnvironment assumes that there is only one EP. -->
<!-- And this file should be removed once 202 is no longer supported -->
<extensionPoints>
<extensionPoint qualifiedName="com.intellij.psi.classFileDecompiler"
interface="com.intellij.psi.compiled.ClassFileDecompilers$Decompiler"
dynamic="true"/>
</extensionPoints>
</idea-plugin>

View File

@@ -1,10 +0,0 @@
<idea-plugin>
<id>org.jetbrains.kotlin</id>
<version>1.2</version>
<extensionPoints>
<extensionPoint qualifiedName="com.intellij.psi.classFileDecompiler"
interface="com.intellij.psi.compiled.ClassFileDecompilers$Decompiler"
dynamic="true"/>
</extensionPoints>
</idea-plugin>

View File

@@ -369,7 +369,6 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
)
var extendedCompilerChecks: Boolean by FreezableVar(false)
@GradleOption(DefaultValues.BooleanFalseDefault::class)
@Argument(
value = "-Xbuiltins-from-sources",
description = "Compile builtIns from sources"

View File

@@ -214,6 +214,12 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
)
var useOldClassFilesReading: Boolean by FreezableVar(false)
@Argument(
value = "-Xuse-fast-jar-file-system",
description = "Use fast implementation on Jar FS. This may speed up compilation time, but currently it's an experimental mode"
)
var useFastJarFileSystem: Boolean by FreezableVar(false)
@Argument(
value = "-Xdump-declarations-to",
valueDescription = "<path>",
@@ -505,6 +511,18 @@ default: `indy-with-constants` for JVM target 9 or greater, `inline` otherwise""
)
var serializeIr: Boolean by FreezableVar(false)
@Argument(
value = "-Xvalidate-ir",
description = "Validate IR before and after lowering"
)
var validateIr: Boolean by FreezableVar(false)
@Argument(
value = "-Xvalidate-bytecode",
description = "Validate generated JVM bytecode before and after optimizations"
)
var validateBytecode: Boolean by FreezableVar(false)
override fun configureAnalysisFlags(collector: MessageCollector, languageVersion: LanguageVersion): MutableMap<AnalysisFlag<*>, Any> {
val result = super.configureAnalysisFlags(collector, languageVersion)
result[JvmAnalysisFlags.strictMetadataVersionSemantics] = strictMetadataVersionSemantics

View File

@@ -38,6 +38,8 @@ import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider
import org.jetbrains.kotlin.incremental.js.IncrementalNextRoundChecker
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer
import org.jetbrains.kotlin.ir.backend.js.*
import org.jetbrains.kotlin.ir.backend.js.ic.buildCache
import org.jetbrains.kotlin.ir.backend.js.ic.checkCaches
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.declarations.persistent.PersistentIrFactory
import org.jetbrains.kotlin.js.config.*
@@ -91,7 +93,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
configuration.put(CommonConfigurationKeys.MODULE_NAME, "repl.kts")
val environment = KotlinCoreEnvironment.getOrCreateApplicationEnvironmentForProduction(rootDisposable, configuration)
val projectEnv = KotlinCoreEnvironment.ProjectEnvironment(rootDisposable, environment)
val projectEnv = KotlinCoreEnvironment.ProjectEnvironment(rootDisposable, environment, configuration)
projectEnv.registerExtensionsFromPlugins(configuration)
val scriptingEvaluators = ScriptEvaluationExtension.getInstances(projectEnv.project)
@@ -179,6 +181,44 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
// TODO: Handle non-empty main call arguments
val mainCallArguments = if (K2JsArgumentConstants.NO_CALL == arguments.main) null else emptyList<String>()
val icCaches = configureLibraries(arguments.cacheDirectories)
if (arguments.irBuildCache) {
messageCollector.report(INFO, "")
messageCollector.report(INFO, "Building cache:")
messageCollector.report(INFO, "to: ${outputFilePath}")
messageCollector.report(INFO, arguments.cacheDirectories ?: "")
messageCollector.report(INFO, libraries.toString())
val includes = arguments.includes!!
// TODO: deduplicate
val mainModule = run {
if (sourcesFiles.isNotEmpty()) {
messageCollector.report(ERROR, "Source files are not supported when -Xinclude is present")
}
MainModule.Klib(includes)
}
val start = System.currentTimeMillis()
if (buildCache(
cachePath = outputFilePath,
project = projectJs,
mainModule = mainModule,
analyzer = AnalyzerWithCompilerReport(config.configuration),
configuration = config.configuration,
dependencies = libraries,
friendDependencies = friendLibraries,
icCache = checkCaches(libraries, icCaches, skipLib = mainModule.libPath)
)
) {
messageCollector.report(INFO, "IC cache building duration: ${System.currentTimeMillis() - start}ms")
} else {
messageCollector.report(INFO, "IC cache up-to-date check duration: ${System.currentTimeMillis() - start}ms")
}
return OK
}
if (arguments.irProduceKlibDir || arguments.irProduceKlibFile) {
if (arguments.irProduceKlibFile) {
require(outputFile.extension == KLIB_FILE_EXTENSION) { "Please set up .klib file as output" }
@@ -199,6 +239,9 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
}
if (arguments.irProduceJs) {
messageCollector.report(INFO,"Produce executable: $outputFilePath")
messageCollector.report(INFO, arguments.cacheDirectories ?: "")
val phaseConfig = createPhaseConfig(jsPhases, arguments, messageCollector)
val includes = arguments.includes
@@ -243,6 +286,8 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
return OK
}
val start = System.currentTimeMillis()
val compiledModule = compile(
projectJs,
mainModule,
@@ -270,8 +315,13 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
arguments.irSafeExternalBooleanDiagnostic,
messageCollector
),
lowerPerModule = icCaches.isNotEmpty(),
useStdlibCache = icCaches.isNotEmpty(),
icCache = if (icCaches.isNotEmpty()) checkCaches(libraries, icCaches, skipLib = includes).data else emptyMap(),
)
messageCollector.report(INFO, "Executable production duration: ${System.currentTimeMillis() - start}ms")
val outputs = if (arguments.irDce && !arguments.irDceDriven) compiledModule.outputsAfterDce!! else compiledModule.outputs!!
outputFile.write(outputs)
outputs.dependencies.forEach { (name, content) ->

View File

@@ -0,0 +1,13 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.util.io;
import org.jetbrains.annotations.NotNull;
import java.nio.channels.FileChannel;
public final class FileChannelUtil {
@NotNull
static FileChannel unInterruptible(@NotNull FileChannel channel) {
return channel;
}
}

View File

@@ -5,9 +5,9 @@
package org.jetbrains.kotlin.cli.common.extensions
import com.intellij.core.JavaCoreProjectEnvironment
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
@@ -22,6 +22,6 @@ interface ScriptEvaluationExtension {
fun eval(
arguments: CommonCompilerArguments,
configuration: CompilerConfiguration,
projectEnvironment: JavaCoreProjectEnvironment
projectEnvironment: KotlinCoreEnvironment.ProjectEnvironment
): ExitCode
}

View File

@@ -233,8 +233,8 @@ object JvmRuntimeVersionsConsistencyChecker {
jars: List<KotlinLibraryFile>
): MavenComparableVersion? {
assert(jars.isNotEmpty()) { "'jars' must not be empty" }
val oldestVersion = jars.minBy { it.version }!!.version
val newestVersion = jars.maxBy { it.version }!!.version
val oldestVersion = jars.minOf { it.version }
val newestVersion = jars.maxOf { it.version }
// If the oldest version is the same as the newest version, then all jars have the same version
if (oldestVersion == newestVersion) return oldestVersion
@@ -250,9 +250,9 @@ object JvmRuntimeVersionsConsistencyChecker {
// we suggest to provide an explicit dependency on version X.
// TODO: report this depending on the content of the jars instead
val minReflectJar =
jars.filter { it.file.name.startsWith("kotlin-reflect") }.minBy { it.version }
jars.filter { it.file.name.startsWith("kotlin-reflect") }.minByOrNull { it.version }
val maxStdlibJar =
jars.filter { it.file.name.startsWith("kotlin-runtime") || it.file.name.startsWith("kotlin-stdlib") }.maxBy { it.version }
jars.filter { it.file.name.startsWith("kotlin-runtime") || it.file.name.startsWith("kotlin-stdlib") }.maxByOrNull { it.version }
if (minReflectJar != null && maxStdlibJar != null && minReflectJar.version < maxStdlibJar.version) {
messageCollector.issue(
null,

View File

@@ -89,7 +89,8 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
val projectEnvironment =
KotlinCoreEnvironment.ProjectEnvironment(
rootDisposable,
KotlinCoreEnvironment.getOrCreateApplicationEnvironmentForProduction(rootDisposable, configuration)
KotlinCoreEnvironment.getOrCreateApplicationEnvironmentForProduction(rootDisposable, configuration),
configuration
)
projectEnvironment.registerExtensionsFromPlugins(configuration)

View File

@@ -235,6 +235,7 @@ object FirKotlinToJvmBytecodeCompiler {
if (commonSession != null) {
sourceDependsOnDependencies(listOf(commonSession.moduleData))
}
friendDependencies(module.getFriendPaths())
}
val commonAnalyzerFacade = commonSession?.let { FirAnalyzerFacade(it, languageVersionSettings, commonKtFiles) }

View File

@@ -1,19 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.cli.jvm.compiler
import com.intellij.openapi.project.DumbUtil
@Suppress("UnstableApiUsage")
class KotlinCoreDumbUtil : DumbUtil {
override fun <T : Any?> filterByDumbAwarenessHonoringIgnoring(collection: Collection<T>): List<T> =
when (collection) {
is List<T> -> collection
else -> ArrayList(collection)
}
override fun mayUseIndices(): Boolean = false
}

View File

@@ -68,6 +68,7 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.STRONG_W
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.toBooleanLenient
import org.jetbrains.kotlin.cli.jvm.JvmRuntimeVersionsConsistencyChecker
import org.jetbrains.kotlin.cli.jvm.compiler.jarfs.FastJarFileSystem
import org.jetbrains.kotlin.cli.jvm.config.*
import org.jetbrains.kotlin.cli.jvm.index.*
import org.jetbrains.kotlin.cli.jvm.javac.JavacWrapperRegistrar
@@ -92,11 +93,11 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer
import org.jetbrains.kotlin.resolve.ModuleAnnotationsResolver
import org.jetbrains.kotlin.resolve.extensions.ExtraImportsProviderExtension
import org.jetbrains.kotlin.resolve.jvm.extensions.SyntheticJavaResolveExtension
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension
import org.jetbrains.kotlin.resolve.jvm.extensions.SyntheticJavaResolveExtension
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
import org.jetbrains.kotlin.resolve.lazy.declarations.CliDeclarationProviderFactoryService
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService
@@ -107,17 +108,54 @@ import java.nio.file.FileSystems
import java.util.zip.ZipFile
class KotlinCoreEnvironment private constructor(
val projectEnvironment: JavaCoreProjectEnvironment,
val projectEnvironment: ProjectEnvironment,
private val initialConfiguration: CompilerConfiguration,
configFiles: EnvironmentConfigFiles
) {
class ProjectEnvironment(
disposable: Disposable,
applicationEnvironment: KotlinCoreApplicationEnvironment
applicationEnvironment: KotlinCoreApplicationEnvironment,
configuration: CompilerConfiguration
) :
KotlinCoreProjectEnvironment(disposable, applicationEnvironment) {
internal val jarFileSystem: VirtualFileSystem
init {
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
if (configuration.getBoolean(JVMConfigurationKeys.USE_FAST_JAR_FILE_SYSTEM)) {
messageCollector?.report(
STRONG_WARNING,
"Using new faster version of JAR FS: it should make your build faster, but the new implementation is experimental"
)
}
jarFileSystem = when {
configuration.getBoolean(JVMConfigurationKeys.USE_FAST_JAR_FILE_SYSTEM) || configuration.getBoolean(CommonConfigurationKeys.USE_FIR) -> {
val fastJarFs = FastJarFileSystem.createIfUnmappingPossible()
if (fastJarFs == null) {
messageCollector?.report(
STRONG_WARNING,
"Your JDK doesn't seem to support mapped buffer unmapping, so the slower (old) version of JAR FS will be used"
)
applicationEnvironment.jarFileSystem
} else {
Disposer.register(disposable) {
fastJarFs.clearHandlersCache()
}
fastJarFs
}
}
else -> applicationEnvironment.jarFileSystem
}
}
private var extensionRegistered = false
override fun preregisterServices() {
@@ -167,6 +205,13 @@ class KotlinCoreEnvironment private constructor(
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
if (configuration.getBoolean(JVMConfigurationKeys.USE_FAST_JAR_FILE_SYSTEM)) {
messageCollector?.report(
STRONG_WARNING,
"Using new faster version of JAR FS: it should make your build faster, but the new implementation is experimental"
)
}
(projectEnvironment as? ProjectEnvironment)?.registerExtensionsFromPlugins(configuration)
// otherwise consider that project environment is properly configured before passing to the environment
// TODO: consider some asserts to check important extension points
@@ -222,11 +267,14 @@ class KotlinCoreEnvironment private constructor(
this.initialRoots.addAll(initialRoots)
if (!configuration.getBoolean(JVMConfigurationKeys.SKIP_RUNTIME_VERSION_CHECK) && messageCollector != null) {
/*
// Temporarily disable until compiler is bootstrapped to 1.6.
JvmRuntimeVersionsConsistencyChecker.checkCompilerClasspathConsistency(
messageCollector,
configuration,
initialRoots.mapNotNull { (file, type) -> if (type == JavaRoot.RootType.BINARY) file else null }
)
*/
}
val (roots, singleJavaFileRoots) =
@@ -391,7 +439,7 @@ class KotlinCoreEnvironment private constructor(
}
private fun findJarRoot(file: File): VirtualFile? =
applicationEnvironment.jarFileSystem.findFileByPath("$file${URLUtil.JAR_SEPARATOR}")
projectEnvironment.jarFileSystem.findFileByPath("$file${URLUtil.JAR_SEPARATOR}")
private fun getSourceRootsCheckingForDuplicates(): List<KotlinSourceRoot> {
val uniqueSourceRoots = hashSetOf<String>()
@@ -417,17 +465,22 @@ class KotlinCoreEnvironment private constructor(
companion object {
private val LOG = Logger.getInstance(KotlinCoreEnvironment::class.java)
private val APPLICATION_LOCK = Object()
@PublishedApi
internal val APPLICATION_LOCK = Object()
private var ourApplicationEnvironment: KotlinCoreApplicationEnvironment? = null
private var ourProjectCount = 0
inline fun <R> underApplicationLock(action: () -> R): R =
synchronized(APPLICATION_LOCK) { action() }
@JvmStatic
fun createForProduction(
parentDisposable: Disposable, configuration: CompilerConfiguration, configFiles: EnvironmentConfigFiles
): KotlinCoreEnvironment {
setupIdeaStandaloneExecution()
val appEnv = getOrCreateApplicationEnvironmentForProduction(parentDisposable, configuration)
val projectEnv = ProjectEnvironment(parentDisposable, appEnv)
val projectEnv = ProjectEnvironment(parentDisposable, appEnv, configuration)
val environment = KotlinCoreEnvironment(projectEnv, configuration, configFiles)
synchronized(APPLICATION_LOCK) {
@@ -438,7 +491,7 @@ class KotlinCoreEnvironment private constructor(
@JvmStatic
fun createForProduction(
projectEnvironment: JavaCoreProjectEnvironment, configuration: CompilerConfiguration, configFiles: EnvironmentConfigFiles
projectEnvironment: ProjectEnvironment, configuration: CompilerConfiguration, configFiles: EnvironmentConfigFiles
): KotlinCoreEnvironment {
val environment = KotlinCoreEnvironment(projectEnvironment, configuration, configFiles)
@@ -459,7 +512,7 @@ class KotlinCoreEnvironment private constructor(
val configuration = initialConfiguration.copy()
// Tests are supposed to create a single project and dispose it right after use
val appEnv = createApplicationEnvironment(parentDisposable, configuration, unitTestMode = true)
val projectEnv = ProjectEnvironment(parentDisposable, appEnv)
val projectEnv = ProjectEnvironment(parentDisposable, appEnv, configuration)
return KotlinCoreEnvironment(projectEnv, configuration, extensionConfigs)
}
@@ -474,7 +527,7 @@ class KotlinCoreEnvironment private constructor(
@TestOnly
fun createProjectEnvironmentForTests(parentDisposable: Disposable, configuration: CompilerConfiguration): ProjectEnvironment {
val appEnv = createApplicationEnvironment(parentDisposable, configuration, unitTestMode = true)
return ProjectEnvironment(parentDisposable, appEnv)
return ProjectEnvironment(parentDisposable, appEnv, configuration)
}
// used in the daemon for jar cache cleanup
@@ -493,7 +546,14 @@ class KotlinCoreEnvironment private constructor(
): KotlinCoreApplicationEnvironment {
synchronized(APPLICATION_LOCK) {
if (ourApplicationEnvironment == null) {
val disposable = Disposer.newDisposable()
val disposable = if (unitTestMode) {
parentDisposable
} else {
// TODO this is a memory leak in the compiler, as this Disposable is not registered and thus is never disposed
// but using parentDisposable as disposable in compiler, causes access to application extension points after
// they was disposed, this needs to be fixed
Disposer.newDisposable("Disposable for the KotlinCoreApplicationEnvironment")
}
ourApplicationEnvironment = createApplicationEnvironment(disposable, configuration, unitTestMode)
ourProjectCount = 0
Disposer.register(disposable, Disposable {
@@ -538,11 +598,6 @@ class KotlinCoreEnvironment private constructor(
val applicationEnvironment = KotlinCoreApplicationEnvironment.create(parentDisposable, unitTestMode)
registerApplicationExtensionPointsAndExtensionsFrom(configuration, "extensions/compiler.xml")
// FIX ME WHEN BUNCH 202 REMOVED: this code is required to support compiler bundled to both 202 and 203.
// Please, remove "com.intellij.psi.classFileDecompiler" EP registration once 202 is no longer supported by the compiler
if (!ApplicationManager.getApplication().extensionArea.hasExtensionPoint("com.intellij.psi.classFileDecompiler")) {
registerApplicationExtensionPointsAndExtensionsFrom(configuration, "extensions/core.xml")
}
registerApplicationServicesForCLI(applicationEnvironment)
registerApplicationServices(applicationEnvironment)

View File

@@ -1,722 +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.cli.jvm.compiler
import com.intellij.codeInsight.ExternalAnnotationsManager
import com.intellij.codeInsight.InferredAnnotationsManager
import com.intellij.core.CoreApplicationEnvironment
import com.intellij.core.CoreJavaFileManager
import com.intellij.core.JavaCoreProjectEnvironment
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.lang.java.JavaParserDefinition
import com.intellij.mock.MockProject
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.TransactionGuard
import com.intellij.openapi.application.TransactionGuardImpl
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.extensions.ExtensionsArea
import com.intellij.openapi.fileTypes.PlainTextFileType
import com.intellij.openapi.project.DumbUtil
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.io.FileUtilRt
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.*
import com.intellij.openapi.vfs.impl.ZipHandler
import com.intellij.psi.PsiElementFinder
import com.intellij.psi.PsiManager
import com.intellij.psi.impl.JavaClassSupersImpl
import com.intellij.psi.impl.PsiElementFinderImpl
import com.intellij.psi.impl.PsiTreeChangePreprocessor
import com.intellij.psi.impl.file.impl.JavaFileManager
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.JavaClassSupers
import com.intellij.util.io.URLUtil
import com.intellij.util.lang.UrlClassLoader
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
import org.jetbrains.kotlin.asJava.classes.FacadeCache
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.CliModuleVisibilityManagerImpl
import org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY
import org.jetbrains.kotlin.cli.common.config.ContentRoot
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots
import org.jetbrains.kotlin.cli.common.extensions.ScriptEvaluationExtension
import org.jetbrains.kotlin.cli.common.extensions.ShellExtension
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.STRONG_WARNING
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.toBooleanLenient
import org.jetbrains.kotlin.cli.jvm.JvmRuntimeVersionsConsistencyChecker
import org.jetbrains.kotlin.cli.jvm.config.*
import org.jetbrains.kotlin.cli.jvm.index.*
import org.jetbrains.kotlin.cli.jvm.javac.JavacWrapperRegistrar
import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleFinder
import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleResolver
import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.extensions.*
import org.jetbrains.kotlin.extensions.internal.CandidateInterceptor
import org.jetbrains.kotlin.extensions.internal.TypeResolutionInterceptor
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.js.translate.extensions.JsSyntheticTranslateExtension
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
import org.jetbrains.kotlin.load.kotlin.MetadataFinderFactory
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer
import org.jetbrains.kotlin.resolve.ModuleAnnotationsResolver
import org.jetbrains.kotlin.resolve.extensions.ExtraImportsProviderExtension
import org.jetbrains.kotlin.resolve.jvm.extensions.SyntheticJavaResolveExtension
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
import org.jetbrains.kotlin.resolve.lazy.declarations.CliDeclarationProviderFactoryService
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService
import org.jetbrains.kotlin.serialization.DescriptorSerializerPlugin
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
import java.nio.file.FileSystems
import java.util.zip.ZipFile
class KotlinCoreEnvironment private constructor(
val projectEnvironment: JavaCoreProjectEnvironment,
initialConfiguration: CompilerConfiguration,
configFiles: EnvironmentConfigFiles
) {
class ProjectEnvironment(
disposable: Disposable, applicationEnvironment: KotlinCoreApplicationEnvironment
) :
KotlinCoreProjectEnvironment(disposable, applicationEnvironment) {
private var extensionRegistered = false
override fun preregisterServices() {
registerProjectExtensionPoints(project.extensionArea)
}
fun registerExtensionsFromPlugins(configuration: CompilerConfiguration) {
if (!extensionRegistered) {
registerPluginExtensionPoints(project)
registerExtensionsFromPlugins(project, configuration)
extensionRegistered = true
}
}
override fun registerJavaPsiFacade() {
with(project) {
registerService(
CoreJavaFileManager::class.java,
ServiceManager.getService(this, JavaFileManager::class.java) as CoreJavaFileManager
)
registerKotlinLightClassSupport(project)
registerService(ExternalAnnotationsManager::class.java, MockExternalAnnotationsManager())
registerService(InferredAnnotationsManager::class.java, MockInferredAnnotationsManager())
}
super.registerJavaPsiFacade()
}
}
private val sourceFiles = mutableListOf<KtFile>()
private val rootsIndex: JvmDependenciesDynamicCompoundIndex
private val packagePartProviders = mutableListOf<JvmPackagePartProvider>()
private val classpathRootsResolver: ClasspathRootsResolver
private val initialRoots = ArrayList<JavaRoot>()
val configuration: CompilerConfiguration = initialConfiguration.apply { setupJdkClasspathRoots(configFiles) }.copy()
init {
PersistentFSConstants::class.java.getDeclaredField("ourMaxIntellisenseFileSize")
.apply { isAccessible = true }
.setInt(null, FileUtilRt.LARGE_FOR_CONTENT_LOADING)
val project = projectEnvironment.project
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
(projectEnvironment as? ProjectEnvironment)?.registerExtensionsFromPlugins(configuration)
// otherwise consider that project environment is properly configured before passing to the environment
// TODO: consider some asserts to check important extension points
project.registerService(DeclarationProviderFactoryService::class.java, CliDeclarationProviderFactoryService(sourceFiles))
val isJvm = configFiles == EnvironmentConfigFiles.JVM_CONFIG_FILES
project.registerService(ModuleVisibilityManager::class.java, CliModuleVisibilityManagerImpl(isJvm))
registerProjectServicesForCLI(projectEnvironment)
registerProjectServices(projectEnvironment.project)
for (extension in CompilerConfigurationExtension.getInstances(project)) {
extension.updateConfiguration(configuration)
}
sourceFiles += createKtFiles(project)
collectAdditionalSources(project)
sourceFiles.sortBy { it.virtualFile.path }
val javaFileManager = ServiceManager.getService(project, CoreJavaFileManager::class.java) as KotlinCliJavaFileManagerImpl
val jdkHome = configuration.get(JVMConfigurationKeys.JDK_HOME)
val jrtFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL)
val javaModuleFinder = CliJavaModuleFinder(
jdkHome?.path?.let { path ->
jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR)
},
javaFileManager
)
val outputDirectory =
configuration.get(JVMConfigurationKeys.MODULES)?.singleOrNull()?.getOutputDirectory()
?: configuration.get(JVMConfigurationKeys.OUTPUT_DIRECTORY)?.absolutePath
classpathRootsResolver = ClasspathRootsResolver(
PsiManager.getInstance(project),
messageCollector,
configuration.getList(JVMConfigurationKeys.ADDITIONAL_JAVA_MODULES),
this::contentRootToVirtualFile,
javaModuleFinder,
!configuration.getBoolean(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE),
outputDirectory?.let(this::findLocalFile),
javaFileManager
)
val (initialRoots, javaModules) =
classpathRootsResolver.convertClasspathRoots(configuration.getList(CLIConfigurationKeys.CONTENT_ROOTS))
this.initialRoots.addAll(initialRoots)
if (!configuration.getBoolean(JVMConfigurationKeys.SKIP_RUNTIME_VERSION_CHECK) && messageCollector != null) {
JvmRuntimeVersionsConsistencyChecker.checkCompilerClasspathConsistency(
messageCollector,
configuration,
initialRoots.mapNotNull { (file, type) -> if (type == JavaRoot.RootType.BINARY) file else null }
)
}
val (roots, singleJavaFileRoots) =
initialRoots.partition { (file) -> file.isDirectory || file.extension != JavaFileType.DEFAULT_EXTENSION }
// REPL and kapt2 update classpath dynamically
rootsIndex = JvmDependenciesDynamicCompoundIndex().apply {
addIndex(JvmDependenciesIndexImpl(roots))
updateClasspathFromRootsIndex(this)
}
javaFileManager.initialize(
rootsIndex,
packagePartProviders,
SingleJavaFileRootsIndex(singleJavaFileRoots),
configuration.getBoolean(JVMConfigurationKeys.USE_PSI_CLASS_FILES_READING)
)
project.registerService(
JavaModuleResolver::class.java,
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules, javaModuleFinder.systemModules.toList(), project)
)
val finderFactory = CliVirtualFileFinderFactory(rootsIndex)
project.registerService(MetadataFinderFactory::class.java, finderFactory)
project.registerService(VirtualFileFinderFactory::class.java, finderFactory)
project.putUserData(APPEND_JAVA_SOURCE_ROOTS_HANDLER_KEY, fun(roots: List<File>) {
updateClasspath(roots.map { JavaSourceRoot(it, null) })
})
}
private fun collectAdditionalSources(project: MockProject) {
var unprocessedSources: Collection<KtFile> = sourceFiles
val processedSources = HashSet<KtFile>()
val processedSourcesByExtension = HashMap<CollectAdditionalSourcesExtension, Collection<KtFile>>()
// repeat feeding extensions with sources while new sources a being added
var sourceCollectionIterations = 0
while (unprocessedSources.isNotEmpty()) {
if (sourceCollectionIterations++ > 10) { // TODO: consider using some appropriate global constant
throw IllegalStateException("Unable to collect additional sources in reasonable number of iterations")
}
processedSources.addAll(unprocessedSources)
val allNewSources = ArrayList<KtFile>()
for (extension in CollectAdditionalSourcesExtension.getInstances(project)) {
// do not feed the extension with the sources it returned on the previous iteration
val sourcesToProcess = unprocessedSources - (processedSourcesByExtension[extension] ?: emptyList())
val newSources = extension.collectAdditionalSourcesAndUpdateConfiguration(sourcesToProcess, configuration, project)
if (newSources.isNotEmpty()) {
allNewSources.addAll(newSources)
processedSourcesByExtension[extension] = newSources
}
}
unprocessedSources = allNewSources.filterNot { processedSources.contains(it) }.distinct()
sourceFiles += unprocessedSources
}
}
fun addKotlinSourceRoots(rootDirs: List<File>) {
val roots = rootDirs.map { KotlinSourceRoot(it.absolutePath, isCommon = false) }
sourceFiles += createSourceFilesFromSourceRoots(configuration, project, roots)
}
fun createPackagePartProvider(scope: GlobalSearchScope): JvmPackagePartProvider {
return JvmPackagePartProvider(configuration.languageVersionSettings, scope).apply {
addRoots(initialRoots, configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY))
packagePartProviders += this
(ModuleAnnotationsResolver.getInstance(project) as CliModuleAnnotationsResolver).addPackagePartProvider(this)
}
}
private val VirtualFile.javaFiles: List<VirtualFile>
get() = mutableListOf<VirtualFile>().apply {
VfsUtilCore.processFilesRecursively(this@javaFiles) { file ->
if (file.fileType == JavaFileType.INSTANCE) {
add(file)
}
true
}
}
private val allJavaFiles: List<File>
get() = configuration.javaSourceRoots
.mapNotNull(this::findLocalFile)
.flatMap { it.javaFiles }
.map { File(it.canonicalPath) }
fun registerJavac(
javaFiles: List<File> = allJavaFiles,
kotlinFiles: List<KtFile> = sourceFiles,
arguments: Array<String>? = null,
bootClasspath: List<File>? = null,
sourcePath: List<File>? = null
): Boolean {
return JavacWrapperRegistrar.registerJavac(
projectEnvironment.project, configuration, javaFiles, kotlinFiles, arguments, bootClasspath, sourcePath,
LightClassGenerationSupport.getInstance(project), packagePartProviders
)
}
private val applicationEnvironment: CoreApplicationEnvironment
get() = projectEnvironment.environment
val project: Project
get() = projectEnvironment.project
internal fun countLinesOfCode(sourceFiles: List<KtFile>): Int =
sourceFiles.sumBy { sourceFile ->
val text = sourceFile.text
StringUtil.getLineBreakCount(text) + (if (StringUtil.endsWithLineBreak(text)) 0 else 1)
}
private fun updateClasspathFromRootsIndex(index: JvmDependenciesIndex) {
index.indexedRoots.forEach {
projectEnvironment.addSourcesToClasspath(it.file)
}
}
fun updateClasspath(contentRoots: List<ContentRoot>): List<File>? {
// TODO: add new Java modules to CliJavaModuleResolver
val newRoots = classpathRootsResolver.convertClasspathRoots(contentRoots).roots
if (packagePartProviders.isEmpty()) {
initialRoots.addAll(newRoots)
} else {
for (packagePartProvider in packagePartProviders) {
packagePartProvider.addRoots(newRoots, configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY))
}
}
return rootsIndex.addNewIndexForRoots(newRoots)?.let { newIndex ->
updateClasspathFromRootsIndex(newIndex)
newIndex.indexedRoots.mapNotNull { (file) ->
VfsUtilCore.virtualToIoFile(VfsUtilCore.getVirtualFileForJar(file) ?: file)
}.toList()
}.orEmpty()
}
private fun contentRootToVirtualFile(root: JvmContentRoot): VirtualFile? =
when (root) {
is JvmClasspathRoot ->
if (root.file.isFile) findJarRoot(root.file) else findExistingRoot(root, "Classpath entry")
is JvmModulePathRoot ->
if (root.file.isFile) findJarRoot(root.file) else findExistingRoot(root, "Java module root")
is JavaSourceRoot ->
findExistingRoot(root, "Java source root")
else ->
throw IllegalStateException("Unexpected root: $root")
}
internal fun findLocalFile(path: String): VirtualFile? =
applicationEnvironment.localFileSystem.findFileByPath(path)
private fun findExistingRoot(root: JvmContentRoot, rootDescription: String): VirtualFile? {
return findLocalFile(root.file.absolutePath).also {
if (it == null) {
report(STRONG_WARNING, "$rootDescription points to a non-existent location: ${root.file}")
}
}
}
private fun findJarRoot(file: File): VirtualFile? =
applicationEnvironment.jarFileSystem.findFileByPath("$file${URLUtil.JAR_SEPARATOR}")
private fun getSourceRootsCheckingForDuplicates(): List<KotlinSourceRoot> {
val uniqueSourceRoots = hashSetOf<String>()
val result = mutableListOf<KotlinSourceRoot>()
for (root in configuration.kotlinSourceRoots) {
if (!uniqueSourceRoots.add(root.path)) {
report(STRONG_WARNING, "Duplicate source root: ${root.path}")
}
result.add(root)
}
return result
}
fun getSourceFiles(): List<KtFile> = sourceFiles
private fun createKtFiles(project: Project): List<KtFile> =
createSourceFilesFromSourceRoots(configuration, project, getSourceRootsCheckingForDuplicates())
internal fun report(severity: CompilerMessageSeverity, message: String) = configuration.report(severity, message)
companion object {
private val LOG = Logger.getInstance(KotlinCoreEnvironment::class.java)
private val APPLICATION_LOCK = Object()
private var ourApplicationEnvironment: KotlinCoreApplicationEnvironment? = null
private var ourProjectCount = 0
@JvmStatic
fun createForProduction(
parentDisposable: Disposable, configuration: CompilerConfiguration, configFiles: EnvironmentConfigFiles
): KotlinCoreEnvironment {
setupIdeaStandaloneExecution()
val appEnv = getOrCreateApplicationEnvironmentForProduction(parentDisposable, configuration)
val projectEnv = ProjectEnvironment(parentDisposable, appEnv)
val environment = KotlinCoreEnvironment(projectEnv, configuration, configFiles)
synchronized(APPLICATION_LOCK) {
ourProjectCount++
}
return environment
}
@JvmStatic
fun createForProduction(
projectEnvironment: JavaCoreProjectEnvironment, configuration: CompilerConfiguration, configFiles: EnvironmentConfigFiles
): KotlinCoreEnvironment {
val environment = KotlinCoreEnvironment(projectEnvironment, configuration, configFiles)
if (projectEnvironment.environment == applicationEnvironment) {
// accounting for core environment disposing
synchronized(APPLICATION_LOCK) {
ourProjectCount++
}
}
return environment
}
@TestOnly
@JvmStatic
fun createForTests(
parentDisposable: Disposable, initialConfiguration: CompilerConfiguration, extensionConfigs: EnvironmentConfigFiles
): KotlinCoreEnvironment {
val configuration = initialConfiguration.copy()
// Tests are supposed to create a single project and dispose it right after use
val appEnv = createApplicationEnvironment(parentDisposable, configuration, unitTestMode = true)
val projectEnv = ProjectEnvironment(parentDisposable, appEnv)
return KotlinCoreEnvironment(projectEnv, configuration, extensionConfigs)
}
@TestOnly
@JvmStatic
fun createForTests(
projectEnvironment: ProjectEnvironment, initialConfiguration: CompilerConfiguration, extensionConfigs: EnvironmentConfigFiles
): KotlinCoreEnvironment {
return KotlinCoreEnvironment(projectEnvironment, initialConfiguration, extensionConfigs)
}
@TestOnly
fun createProjectEnvironmentForTests(parentDisposable: Disposable, configuration: CompilerConfiguration): ProjectEnvironment {
val appEnv = createApplicationEnvironment(parentDisposable, configuration, unitTestMode = true)
return ProjectEnvironment(parentDisposable, appEnv)
}
// used in the daemon for jar cache cleanup
val applicationEnvironment: KotlinCoreApplicationEnvironment? get() = ourApplicationEnvironment
fun getOrCreateApplicationEnvironmentForProduction(
parentDisposable: Disposable, configuration: CompilerConfiguration
): KotlinCoreApplicationEnvironment = getOrCreateApplicationEnvironment(parentDisposable, configuration, unitTestMode = false)
fun getOrCreateApplicationEnvironmentForTests(
parentDisposable: Disposable, configuration: CompilerConfiguration
): KotlinCoreApplicationEnvironment = getOrCreateApplicationEnvironment(parentDisposable, configuration, unitTestMode = true)
private fun getOrCreateApplicationEnvironment(
parentDisposable: Disposable, configuration: CompilerConfiguration, unitTestMode: Boolean
): KotlinCoreApplicationEnvironment {
synchronized(APPLICATION_LOCK) {
if (ourApplicationEnvironment == null) {
val disposable = Disposer.newDisposable()
ourApplicationEnvironment = createApplicationEnvironment(disposable, configuration, unitTestMode)
ourProjectCount = 0
Disposer.register(disposable, Disposable {
synchronized(APPLICATION_LOCK) {
ourApplicationEnvironment = null
}
})
}
// Disposing of the environment is unsafe in production then parallel builds are enabled, but turning it off universally
// breaks a lot of tests, therefore it is disabled for production and enabled for tests
if (System.getProperty(KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY).toBooleanLenient() != true) {
// JPS may run many instances of the compiler in parallel (there's an option for compiling independent modules in parallel in IntelliJ)
// All projects share the same ApplicationEnvironment, and when the last project is disposed, the ApplicationEnvironment is disposed as well
Disposer.register(parentDisposable, Disposable {
synchronized(APPLICATION_LOCK) {
if (--ourProjectCount <= 0) {
disposeApplicationEnvironment()
}
}
})
}
return ourApplicationEnvironment!!
}
}
private fun disposeApplicationEnvironment() {
synchronized(APPLICATION_LOCK) {
val environment = ourApplicationEnvironment ?: return
ourApplicationEnvironment = null
Disposer.dispose(environment.parentDisposable)
ZipHandler.clearFileAccessorCache()
}
}
private fun createApplicationEnvironment(
parentDisposable: Disposable, configuration: CompilerConfiguration, unitTestMode: Boolean
): KotlinCoreApplicationEnvironment {
val applicationEnvironment = KotlinCoreApplicationEnvironment.create(parentDisposable, unitTestMode)
registerApplicationExtensionPointsAndExtensionsFrom(configuration, "extensions/compiler.xml")
registerApplicationExtensionPointsAndExtensionsFrom(configuration, "extensions/core.xml")
registerApplicationServicesForCLI(applicationEnvironment)
registerApplicationServices(applicationEnvironment)
return applicationEnvironment
}
private fun registerApplicationExtensionPointsAndExtensionsFrom(configuration: CompilerConfiguration, configFilePath: String) {
fun File.hasConfigFile(configFile: String): Boolean =
if (isDirectory) File(this, "META-INF" + File.separator + configFile).exists()
else try {
ZipFile(this).use {
it.getEntry("META-INF/$configFile") != null
}
} catch (e: Throwable) {
false
}
val pluginRoot: File =
configuration.get(CLIConfigurationKeys.INTELLIJ_PLUGIN_ROOT)?.let(::File)
?: PathUtil.getResourcePathForClass(this::class.java).takeIf { it.hasConfigFile(configFilePath) }
// hack for load extensions when compiler run directly from project directory (e.g. in tests)
?: File("compiler/cli/cli-common/resources").takeIf { it.hasConfigFile(configFilePath) }
?: throw IllegalStateException(
"Unable to find extension point configuration $configFilePath " +
"(cp:\n ${(Thread.currentThread().contextClassLoader as? UrlClassLoader)?.urls?.joinToString("\n ") { it.file }})"
)
CoreApplicationEnvironment.registerExtensionPointAndExtensions(
FileSystems.getDefault().getPath(pluginRoot.path),
configFilePath,
ApplicationManager.getApplication().extensionArea
)
}
@JvmStatic
@Suppress("MemberVisibilityCanPrivate") // made public for CLI Android Lint
fun registerPluginExtensionPoints(project: MockProject) {
ExpressionCodegenExtension.registerExtensionPoint(project)
SyntheticResolveExtension.registerExtensionPoint(project)
SyntheticJavaResolveExtension.registerExtensionPoint(project)
ClassBuilderInterceptorExtension.registerExtensionPoint(project)
AnalysisHandlerExtension.registerExtensionPoint(project)
PackageFragmentProviderExtension.registerExtensionPoint(project)
StorageComponentContainerContributor.registerExtensionPoint(project)
DeclarationAttributeAltererExtension.registerExtensionPoint(project)
PreprocessedVirtualFileFactoryExtension.registerExtensionPoint(project)
JsSyntheticTranslateExtension.registerExtensionPoint(project)
CompilerConfigurationExtension.registerExtensionPoint(project)
CollectAdditionalSourcesExtension.registerExtensionPoint(project)
ExtraImportsProviderExtension.registerExtensionPoint(project)
IrGenerationExtension.registerExtensionPoint(project)
ScriptEvaluationExtension.registerExtensionPoint(project)
ShellExtension.registerExtensionPoint(project)
TypeResolutionInterceptor.registerExtensionPoint(project)
CandidateInterceptor.registerExtensionPoint(project)
DescriptorSerializerPlugin.registerExtensionPoint(project)
}
internal fun registerExtensionsFromPlugins(project: MockProject, configuration: CompilerConfiguration) {
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
for (registrar in configuration.getList(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS)) {
try {
registrar.registerProjectComponents(project, configuration)
} catch (e: AbstractMethodError) {
val message = "The provided plugin ${registrar.javaClass.name} is not compatible with this version of compiler"
// Since the scripting plugin is often discovered in the compiler environment, it is often taken from the incompatible
// location, and in many cases this is not a fatal error, therefore strong warning is generated instead of exception
if (registrar.javaClass.simpleName == "ScriptingCompilerConfigurationComponentRegistrar") {
messageCollector?.report(STRONG_WARNING, "Default scripting plugin is disabled: $message")
} else {
throw IllegalStateException(message, e)
}
}
}
}
private fun registerApplicationServicesForCLI(applicationEnvironment: KotlinCoreApplicationEnvironment) {
// ability to get text from annotations xml files
applicationEnvironment.registerFileType(PlainTextFileType.INSTANCE, "xml")
applicationEnvironment.registerParserDefinition(JavaParserDefinition())
}
// made public for Upsource
@Suppress("MemberVisibilityCanBePrivate")
@JvmStatic
fun registerApplicationServices(applicationEnvironment: KotlinCoreApplicationEnvironment) {
with(applicationEnvironment) {
registerFileType(KotlinFileType.INSTANCE, "kt")
registerFileType(KotlinFileType.INSTANCE, KotlinParserDefinition.STD_SCRIPT_SUFFIX)
registerParserDefinition(KotlinParserDefinition())
application.registerService(KotlinBinaryClassCache::class.java, KotlinBinaryClassCache())
application.registerService(JavaClassSupers::class.java, JavaClassSupersImpl::class.java)
application.registerService(TransactionGuard::class.java, TransactionGuardImpl::class.java)
}
}
@JvmStatic
fun registerProjectExtensionPoints(area: ExtensionsArea) {
CoreApplicationEnvironment.registerExtensionPoint(
area, PsiTreeChangePreprocessor.EP.name, PsiTreeChangePreprocessor::class.java
)
CoreApplicationEnvironment.registerExtensionPoint(area, PsiElementFinder.EP.name, PsiElementFinder::class.java)
IdeaExtensionPoints.registerVersionSpecificProjectExtensionPoints(area)
}
// made public for Upsource
@JvmStatic
@Deprecated("Use registerProjectServices(project) instead.", ReplaceWith("registerProjectServices(projectEnvironment.project)"))
fun registerProjectServices(
projectEnvironment: JavaCoreProjectEnvironment,
@Suppress("UNUSED_PARAMETER") messageCollector: MessageCollector?
) {
registerProjectServices(projectEnvironment.project)
}
// made public for Android Lint
@JvmStatic
fun registerProjectServices(project: MockProject) {
with(project) {
registerService(KotlinJavaPsiFacade::class.java, KotlinJavaPsiFacade(this))
registerService(FacadeCache::class.java, FacadeCache(this))
registerService(ModuleAnnotationsResolver::class.java, CliModuleAnnotationsResolver())
}
}
private fun registerProjectServicesForCLI(@Suppress("UNUSED_PARAMETER") projectEnvironment: JavaCoreProjectEnvironment) {
/**
* Note that Kapt may restart code analysis process, and CLI services should be aware of that.
* Use PsiManager.getModificationTracker() to ensure that all the data you cached is still valid.
*/
}
// made public for Android Lint
@JvmStatic
fun registerKotlinLightClassSupport(project: MockProject) {
with(project) {
val traceHolder = CliTraceHolder()
val cliLightClassGenerationSupport = CliLightClassGenerationSupport(traceHolder, project)
val kotlinAsJavaSupport = CliKotlinAsJavaSupport(this, traceHolder)
registerService(LightClassGenerationSupport::class.java, cliLightClassGenerationSupport)
registerService(CliLightClassGenerationSupport::class.java, cliLightClassGenerationSupport)
registerService(KotlinAsJavaSupport::class.java, kotlinAsJavaSupport)
registerService(CodeAnalyzerInitializer::class.java, traceHolder)
@Suppress("UnstableApiUsage")
registerService(DumbUtil::class.java, KotlinCoreDumbUtil())
// We don't pass Disposable because in some tests, we manually unregister these extensions, and that leads to LOG.error
// exception from `ExtensionPointImpl.doRegisterExtension`, because the registered extension can no longer be found
// when the project is being disposed.
// For example, see the `unregisterExtension` call in `GenerationUtils.compileFilesUsingFrontendIR`.
// TODO: refactor this to avoid registering unneeded extensions in the first place, and avoid using deprecated API.
@Suppress("DEPRECATION")
PsiElementFinder.EP.getPoint(project).registerExtension(JavaElementFinder(this))
@Suppress("DEPRECATION")
PsiElementFinder.EP.getPoint(project).registerExtension(PsiElementFinderImpl(this))
}
}
private fun CompilerConfiguration.setupJdkClasspathRoots(configFiles: EnvironmentConfigFiles) {
if (getBoolean(JVMConfigurationKeys.NO_JDK)) return
val jvmTarget = configFiles == EnvironmentConfigFiles.JVM_CONFIG_FILES
if (!jvmTarget) return
val jdkHome = get(JVMConfigurationKeys.JDK_HOME)
val (javaRoot, classesRoots) = if (jdkHome == null) {
val javaHome = File(System.getProperty("java.home"))
put(JVMConfigurationKeys.JDK_HOME, javaHome)
javaHome to PathUtil.getJdkClassesRootsFromCurrentJre()
} else {
jdkHome to PathUtil.getJdkClassesRoots(jdkHome)
}
if (!CoreJrtFileSystem.isModularJdk(javaRoot)) {
if (classesRoots.isEmpty()) {
report(ERROR, "No class roots are found in the JDK path: $javaRoot")
} else {
addJvmSdkRoots(classesRoots)
}
}
}
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.cli.jvm.compiler.jarfs
import com.intellij.openapi.util.Couple
import com.intellij.openapi.vfs.DeprecatedVirtualFileSystem
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.util.containers.ConcurrentFactoryMap
import com.intellij.util.io.FileAccessorCache
import java.io.File
import java.io.IOException
import java.io.RandomAccessFile
import java.nio.ByteBuffer
import java.nio.MappedByteBuffer
import java.nio.channels.FileChannel
private typealias RandomAccessFileAndBuffer = Pair<RandomAccessFile, MappedByteBuffer>
class FastJarFileSystem private constructor(internal val unmapBuffer: MappedByteBuffer.() -> Unit) : DeprecatedVirtualFileSystem() {
private val myHandlers: MutableMap<String, FastJarHandler> =
ConcurrentFactoryMap.createMap { key: String -> FastJarHandler(this@FastJarFileSystem, key) }
internal val cachedOpenFileHandles: FileAccessorCache<File, RandomAccessFileAndBuffer> =
object : FileAccessorCache<File, RandomAccessFileAndBuffer>(20, 10) {
@Throws(IOException::class)
override fun createAccessor(file: File): RandomAccessFileAndBuffer {
val randomAccessFile = RandomAccessFile(file, "r")
return Pair(randomAccessFile, randomAccessFile.channel.map(FileChannel.MapMode.READ_ONLY, 0, randomAccessFile.length()))
}
@Throws(IOException::class)
override fun disposeAccessor(fileAccessor: RandomAccessFileAndBuffer) {
fileAccessor.first.close()
fileAccessor.second.unmapBuffer()
}
override fun isEqual(val1: File, val2: File): Boolean {
return val1 == val2 // reference equality to handle different jars for different ZipHandlers on the same path
}
}
override fun getProtocol(): String {
return StandardFileSystems.JAR_PROTOCOL
}
override fun findFileByPath(path: String): VirtualFile? {
val pair = splitPath(path)
return myHandlers[pair.first]!!.findFileByPath(pair.second)
}
override fun refresh(asynchronous: Boolean) {}
override fun refreshAndFindFileByPath(path: String): VirtualFile? {
return findFileByPath(path)
}
fun clearHandlersCache() {
myHandlers.clear()
cachedOpenFileHandles.clear()
}
companion object {
fun splitPath(path: String): Couple<String> {
val separator = path.indexOf("!/")
require(separator >= 0) { "Path in JarFileSystem must contain a separator: $path" }
val localPath = path.substring(0, separator)
val pathInJar = path.substring(separator + 2)
return Couple.of(localPath, pathInJar)
}
fun createIfUnmappingPossible(): FastJarFileSystem? {
val cleanerCallBack = prepareCleanerCallback() ?: return null
return FastJarFileSystem(cleanerCallBack)
}
}
}
private val IS_PRIOR_9_JRE = System.getProperty("java.specification.version", "").startsWith("1.")
private fun prepareCleanerCallback(): ((ByteBuffer) -> Unit)? {
return try {
if (IS_PRIOR_9_JRE) {
val cleaner = Class.forName("java.nio.DirectByteBuffer").getMethod("cleaner")
cleaner.isAccessible = true
val clean = Class.forName("sun.misc.Cleaner").getMethod("clean")
clean.isAccessible = true
{ buffer: ByteBuffer -> clean.invoke(cleaner.invoke(buffer)) }
} else {
val unsafeClass = try {
Class.forName("sun.misc.Unsafe")
} catch (ex: Exception) {
// jdk.internal.misc.Unsafe doesn't yet have an invokeCleaner() method,
// but that method should be added if sun.misc.Unsafe is removed.
Class.forName("jdk.internal.misc.Unsafe")
}
val clean = unsafeClass.getMethod("invokeCleaner", ByteBuffer::class.java)
clean.isAccessible = true
val theUnsafeField = unsafeClass.getDeclaredField("theUnsafe")
theUnsafeField.isAccessible = true
val theUnsafe = theUnsafeField.get(null);
{ buffer: ByteBuffer -> clean.invoke(theUnsafe, buffer) }
}
} catch (ex: Exception) {
null
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.cli.jvm.compiler.jarfs
import com.intellij.openapi.vfs.VirtualFile
import java.io.File
import java.io.FileNotFoundException
import java.io.RandomAccessFile
import java.nio.channels.FileChannel
class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) {
private val myRoot: VirtualFile?
internal val file = File(path)
private val ourEntryMap: Map<String, ZipEntryDescription>
private val cachedManifest: ByteArray?
init {
RandomAccessFile(file, "r").use { randomAccessFile ->
val mappedByteBuffer = randomAccessFile.channel.map(FileChannel.MapMode.READ_ONLY, 0, randomAccessFile.length())
try {
ourEntryMap = mappedByteBuffer.parseCentralDirectory().associateBy { it.relativePath }
cachedManifest = ourEntryMap[MANIFEST_PATH]?.let(mappedByteBuffer::contentsToByteArray)
} finally {
with(fileSystem) {
mappedByteBuffer.unmapBuffer()
}
}
}
myRoot = FastJarVirtualFile(this, "", -1, null)
val filesByRelativePath = HashMap<String, FastJarVirtualFile>(ourEntryMap.size)
filesByRelativePath[""] = myRoot
for (entryDescription in ourEntryMap.values) {
if (!entryDescription.isDirectory) {
createFile(entryDescription, filesByRelativePath)
} else {
getOrCreateDirectory(entryDescription.relativePath, filesByRelativePath)
}
}
for (node in filesByRelativePath.values) {
node.initChildrenArrayFromList()
}
}
private fun createFile(entry: ZipEntryDescription, directories: MutableMap<String, FastJarVirtualFile>): FastJarVirtualFile {
val (parentName, shortName) = entry.relativePath.splitPath()
val parentFile = getOrCreateDirectory(parentName, directories)
if ("." == shortName) {
return parentFile
}
return FastJarVirtualFile(
this, shortName,
if (entry.isDirectory) -1 else entry.uncompressedSize,
parentFile
)
}
private fun getOrCreateDirectory(entryName: String, directories: MutableMap<String, FastJarVirtualFile>): FastJarVirtualFile {
return directories.getOrPut(entryName) {
val (parentPath, shortName) = entryName.splitPath()
val parentFile = getOrCreateDirectory(parentPath, directories)
FastJarVirtualFile(this, shortName, -1, parentFile)
}
}
private fun String.splitPath(): Pair<String, String> {
var slashIndex = this.length - 1
while (slashIndex >= 0 && this[slashIndex] != '/') {
slashIndex--
}
if (slashIndex == -1) return Pair("", this)
return Pair(substring(0, slashIndex), substring(slashIndex + 1))
}
fun findFileByPath(pathInJar: String): VirtualFile? {
return myRoot?.findFileByRelativePath(pathInJar)
}
fun contentsToByteArray(relativePath: String): ByteArray {
if (relativePath == MANIFEST_PATH) return cachedManifest ?: throw FileNotFoundException("$file!/$relativePath")
val zipEntryDescription = ourEntryMap[relativePath] ?: throw FileNotFoundException("$file!/$relativePath")
return fileSystem.cachedOpenFileHandles[file].use {
synchronized(it) {
it.get().second.contentsToByteArray(zipEntryDescription)
}
}
}
}
private const val MANIFEST_PATH = "META-INF/MANIFEST.MF"

View File

@@ -0,0 +1,108 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.cli.jvm.compiler.jarfs
import com.intellij.openapi.util.Couple
import com.intellij.openapi.util.io.BufferExposingByteArrayInputStream
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileSystem
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
internal class FastJarVirtualFile(
private val myHandler: FastJarHandler,
private val myName: CharSequence,
private val myLength: Int,
private val myParent: FastJarVirtualFile?
) : VirtualFile() {
private var myChildrenArray = EMPTY_ARRAY
private val myChildrenList: MutableList<VirtualFile> = mutableListOf()
init {
myParent?.myChildrenList?.add(this)
}
fun initChildrenArrayFromList() {
myChildrenArray = myChildrenList.toTypedArray()
myChildrenList.clear()
}
override fun getName(): String {
return myName.toString()
}
override fun getNameSequence(): CharSequence {
return myName
}
override fun getFileSystem(): VirtualFileSystem {
return myHandler.fileSystem
}
override fun getPath(): String {
if (myParent == null) {
return FileUtil.toSystemIndependentName(myHandler.file.path) + "!/"
}
val parentPath = myParent.path
val answer = StringBuilder(parentPath.length + 1 + myName.length)
answer.append(parentPath)
if (answer[answer.length - 1] != '/') {
answer.append('/')
}
answer.append(myName)
return answer.toString()
}
override fun isWritable(): Boolean {
return false
}
override fun isDirectory(): Boolean {
return myLength < 0
}
override fun isValid(): Boolean {
return true
}
override fun getParent(): VirtualFile? {
return myParent
}
override fun getChildren(): Array<VirtualFile> {
return myChildrenArray
}
@Throws(IOException::class)
override fun getOutputStream(requestor: Any, newModificationStamp: Long, newTimeStamp: Long): OutputStream {
throw UnsupportedOperationException("JarFileSystem is read-only")
}
@Throws(IOException::class)
override fun contentsToByteArray(): ByteArray {
val pair: Couple<String> = FastJarFileSystem.splitPath(
path
)
return myHandler.contentsToByteArray(pair.second)
}
override fun getTimeStamp(): Long = 0
override fun getLength(): Long = myLength.toLong()
override fun refresh(asynchronous: Boolean, recursive: Boolean, postRunnable: Runnable?) {}
@Throws(IOException::class)
override fun getInputStream(): InputStream {
return BufferExposingByteArrayInputStream(contentsToByteArray())
}
override fun getModificationStamp(): Long {
return 0
}
}

View File

@@ -0,0 +1,129 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.cli.jvm.compiler.jarfs
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.MappedByteBuffer
import java.util.zip.Inflater
class ZipEntryDescription(
val relativePath: String,
val compressedSize: Int,
val uncompressedSize: Int,
val offsetInFile: Int,
val compressionKind: CompressionKind,
val fileNameSize: Int
) {
enum class CompressionKind {
PLAIN, DEFLATE
}
val isDirectory get() = uncompressedSize == 0
}
private const val END_OF_CENTRAL_DIR_SIZE = 22
private const val LOCAL_FILE_HEADER_EXTRA_OFFSET = 28
private const val LOCAL_FILE_HEADER_SIZE = LOCAL_FILE_HEADER_EXTRA_OFFSET + 2
fun MappedByteBuffer.contentsToByteArray(
zipEntryDescription: ZipEntryDescription
): ByteArray {
order(ByteOrder.LITTLE_ENDIAN)
val extraSize =
getUnsignedShort(zipEntryDescription.offsetInFile + LOCAL_FILE_HEADER_EXTRA_OFFSET)
position(
zipEntryDescription.offsetInFile + LOCAL_FILE_HEADER_SIZE + zipEntryDescription.fileNameSize + extraSize
)
val compressed = ByteArray(zipEntryDescription.compressedSize + 1)
get(compressed, 0, zipEntryDescription.compressedSize)
return when (zipEntryDescription.compressionKind) {
ZipEntryDescription.CompressionKind.DEFLATE -> {
val inflater = Inflater(true)
inflater.setInput(compressed, 0, zipEntryDescription.compressedSize)
val result = ByteArray(zipEntryDescription.uncompressedSize)
inflater.inflate(result)
result
}
ZipEntryDescription.CompressionKind.PLAIN -> compressed.copyOf(zipEntryDescription.compressedSize)
}
}
fun MappedByteBuffer.parseCentralDirectory(): List<ZipEntryDescription> {
order(ByteOrder.LITTLE_ENDIAN)
val endOfCentralDirectoryOffset = (capacity() - END_OF_CENTRAL_DIR_SIZE downTo 0).first { offset ->
// header of "End of central directory"
getInt(offset) == 0x06054b50
}
val entriesNumber = getUnsignedShort(endOfCentralDirectoryOffset + 10)
val offsetOfCentralDirectory = getInt(endOfCentralDirectoryOffset + 16)
var currentOffset = offsetOfCentralDirectory
val result = mutableListOf<ZipEntryDescription>()
for (i in 0 until entriesNumber) {
val headerConst = getInt(currentOffset)
require(headerConst == 0x02014b50) {
"$i: $headerConst"
}
val versionNeededToExtract =
getShort(currentOffset + 6).toInt()
val compressionMethod = getShort(currentOffset + 10).toInt()
val compressedSize = getInt(currentOffset + 20)
val uncompressedSize = getInt(currentOffset + 24)
val fileNameLength = getUnsignedShort(currentOffset + 28).toInt()
val extraLength = getUnsignedShort(currentOffset + 30).toInt()
val fileCommentLength = getUnsignedShort(currentOffset + 32).toInt()
val offsetOfFileData = getInt(currentOffset + 42)
val bytesForName = ByteArray(fileNameLength)
position(currentOffset + 46)
get(bytesForName)
val name =
if (bytesForName.all { it >= 0 })
String(bytesForName.asASCICharArray())
else
String(bytesForName, Charsets.UTF_8)
currentOffset += 46 + fileNameLength + extraLength + fileCommentLength
require(versionNeededToExtract == 10 || versionNeededToExtract == 20) {
"Unexpected versionNeededToExtract ($versionNeededToExtract) at $name"
}
val compressionKind = when (compressionMethod) {
0 -> ZipEntryDescription.CompressionKind.PLAIN
8 -> ZipEntryDescription.CompressionKind.DEFLATE
else -> error("Unexpected compression method ($compressionMethod) at $name")
}
result += ZipEntryDescription(
name, compressedSize, uncompressedSize, offsetOfFileData, compressionKind,
fileNameLength
)
}
return result
}
private fun ByteArray.asASCICharArray(): CharArray = CharArray(size) { this@asASCICharArray[it].toChar() }
private fun ByteBuffer.getUnsignedShort(offset: Int): Int = java.lang.Short.toUnsignedInt(getShort(offset))

View File

@@ -254,6 +254,9 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr
put(JVMConfigurationKeys.SERIALIZE_IR, arguments.serializeIr)
put(JVMConfigurationKeys.VALIDATE_IR, arguments.validateIr)
put(JVMConfigurationKeys.VALIDATE_BYTECODE, arguments.validateBytecode)
if (!JVMConstructorCallNormalizationMode.isSupportedValue(arguments.constructorCallNormalizationMode)) {
messageCollector.report(
ERROR,
@@ -280,11 +283,16 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr
put(JVMConfigurationKeys.USE_TYPE_TABLE, arguments.useTypeTable)
put(JVMConfigurationKeys.SKIP_RUNTIME_VERSION_CHECK, arguments.skipRuntimeVersionCheck)
put(JVMConfigurationKeys.USE_PSI_CLASS_FILES_READING, arguments.useOldClassFilesReading)
put(JVMConfigurationKeys.USE_FAST_JAR_FILE_SYSTEM, arguments.useFastJarFileSystem)
if (arguments.useOldClassFilesReading) {
messageCollector.report(INFO, "Using the old java class files reading implementation")
}
if (arguments.useFastJarFileSystem) {
messageCollector.report(INFO, "Using fast Jar FS implementation")
}
put(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE, arguments.allowKotlinPackage)
put(JVMConfigurationKeys.USE_SINGLE_MODULE, arguments.singleModule)
put(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS, arguments.useOldSpilledVarTypeAnalysis)

View File

@@ -99,6 +99,9 @@ public class JVMConfigurationKeys {
public static final CompilerConfigurationKey<Boolean> USE_PSI_CLASS_FILES_READING =
CompilerConfigurationKey.create("use a slower (PSI-based) class files reading implementation");
public static final CompilerConfigurationKey<Boolean> USE_FAST_JAR_FILE_SYSTEM =
CompilerConfigurationKey.create("use a faster JAR filesystem implementation");
public static final CompilerConfigurationKey<Boolean> USE_JAVAC =
CompilerConfigurationKey.create("use javac [experimental]");
@@ -154,5 +157,11 @@ public class JVMConfigurationKeys {
CompilerConfigurationKey.create("Don't automatically include kotlin-reflect.jar into the output if the output is a jar");
public static final CompilerConfigurationKey<Boolean> SERIALIZE_IR =
CompilerConfigurationKey.create("serialize IR to class metadata");
CompilerConfigurationKey.create("Serialize IR to class metadata");
public static final CompilerConfigurationKey<Boolean> VALIDATE_IR =
CompilerConfigurationKey.create("Validate IR");
public static final CompilerConfigurationKey<Boolean> VALIDATE_BYTECODE =
CompilerConfigurationKey.create("Validate generated JVM bytecode");
}

View File

@@ -33,6 +33,7 @@ enum class JvmTarget(
JVM_14("14", Opcodes.V12 + 2),
JVM_15("15", Opcodes.V12 + 3),
JVM_16("16", Opcodes.V12 + 4),
JVM_17("17", Opcodes.V12 + 5),
;
companion object {

View File

@@ -49,7 +49,7 @@ dependencies {
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
kotlinOptions {
apiVersion = "1.3"
apiVersion = "1.4"
freeCompilerArgs += "-Xsuppress-version-warnings"
}
}

View File

@@ -40,8 +40,8 @@ dependencies {
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
kotlinOptions {
// This module is being run from within Gradle, older versions of which only have kotlin-stdlib 1.3 in the runtime classpath.
apiVersion = "1.3"
// This module is being run from within Gradle, older versions of which only have older kotlin-stdlib in the runtime classpath.
apiVersion = "1.4"
freeCompilerArgs += "-Xsuppress-version-warnings"
}
}

View File

@@ -377,7 +377,7 @@ object KotlinCompilerClient {
val javaVersion = CompilerSystemProperties.JAVA_VERSION.value?.toIntOrNull()
val javaIllegalAccessWorkaround =
if (javaVersion != null && javaVersion >= 16)
listOf("--illegal-access=permit")
listOf("--add-exports", "java.base/sun.nio.ch=ALL-UNNAMED")
else emptyList()
val args = listOf(
javaExecutable.absolutePath, "-cp", compilerId.compilerClasspath.joinToString(File.pathSeparator)) +

View File

@@ -21,9 +21,7 @@ import com.intellij.openapi.util.Disposer
import com.intellij.openapi.vfs.impl.ZipHandler
import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
import org.jetbrains.kotlin.build.report.BuildReporter
import org.jetbrains.kotlin.build.report.RemoteBuildReporter
import org.jetbrains.kotlin.build.report.RemoteReporter
import org.jetbrains.kotlin.cli.common.CLICompiler
import org.jetbrains.kotlin.cli.common.CompilerSystemProperties
import org.jetbrains.kotlin.cli.common.ExitCode
@@ -37,10 +35,15 @@ import org.jetbrains.kotlin.cli.common.repl.ReplEvalResult
import org.jetbrains.kotlin.cli.js.K2JSCompiler
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.jarfs.FastJarFileSystem
import org.jetbrains.kotlin.cli.jvm.compiler.jarfs.FastJarHandler
import org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.daemon.report.*
import org.jetbrains.kotlin.daemon.report.CompileServicesFacadeMessageCollector
import org.jetbrains.kotlin.daemon.report.DaemonMessageReporter
import org.jetbrains.kotlin.daemon.report.DaemonMessageReporterPrintStreamAdapter
import org.jetbrains.kotlin.daemon.report.getBuildReporter
import org.jetbrains.kotlin.incremental.*
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker

View File

@@ -66,7 +66,8 @@ abstract class KotlinJvmReplServiceBase(
val projectEnvironment =
KotlinCoreEnvironment.ProjectEnvironment(
disposable,
KotlinCoreEnvironment.getOrCreateApplicationEnvironmentForProduction(disposable, configuration)
KotlinCoreEnvironment.getOrCreateApplicationEnvironmentForProduction(disposable, configuration),
configuration,
)
ReplFactoryExtension.registerExtensionPoint(projectEnvironment.project)
projectEnvironment.registerExtensionsFromPlugins(configuration)
@@ -223,4 +224,4 @@ fun CompilerConfiguration.configureScripting(compilerId: CompilerId) {
error
)
}
}
}

View File

@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult
import org.jetbrains.kotlin.cli.js.K2JSCompiler
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.jarfs.FastJarFileSystem
import org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.daemon.CompileServiceImplBase

View File

@@ -36,12 +36,7 @@ dependencies {
includeJars("jna", rootProject = rootProject)
}
Platform[202] {
testRuntimeOnly(intellijDep()) { includeJars("intellij-deps-fastutil-8.3.1-1") }
}
Platform[203].orHigher {
testRuntimeOnly(intellijDep()) { includeJars("intellij-deps-fastutil-8.4.1-4") }
}
testRuntimeOnly(intellijDep()) { includeJars("intellij-deps-fastutil-8.4.1-4") }
testRuntimeOnly(toolsJar())
}

View File

@@ -29,6 +29,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@TestMetadata("annotationOnDeclarationWithDifferentArguments.kt")
public void testAnnotationOnDeclarationWithDifferentArguments() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/annotationOnDeclarationWithDifferentArguments.kt");
}
@TestMetadata("annotationUsedAsAnnotationArgument.kt")
public void testAnnotationUsedAsAnnotationArgument() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/annotationUsedAsAnnotationArgument.kt");
@@ -64,6 +69,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
runTest("compiler/fir/analysis-tests/testData/resolve/catchParameter.kt");
}
@TestMetadata("classCallInLambda.kt")
public void testClassCallInLambda() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/classCallInLambda.kt");
}
@TestMetadata("companion.kt")
public void testCompanion() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/companion.kt");
@@ -2575,6 +2585,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/localClasses"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@TestMetadata("anonymousInAnonymous.kt")
public void testAnonymousInAnonymous() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/localClasses/anonymousInAnonymous.kt");
}
@TestMetadata("implicitInAnonymous.kt")
public void testImplicitInAnonymous() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/localClasses/implicitInAnonymous.kt");

View File

@@ -0,0 +1,54 @@
FILE: annotationOnDeclarationWithDifferentArguments.kt
public final enum class SomeEnum : R|kotlin/Enum<SomeEnum>| {
private constructor(): R|SomeEnum| {
super<R|kotlin/Enum<SomeEnum>|>()
}
public final static enum entry A: R|SomeEnum|
public final static enum entry B: R|SomeEnum|
public final static fun values(): R|kotlin/Array<SomeEnum>| {
}
public final static fun valueOf(value: R|kotlin/String|): R|SomeEnum| {
}
}
public final annotation class MyAnnotation : R|kotlin/Annotation| {
public constructor(intValue: R|kotlin/Int|, stringValue: R|kotlin/String|, enumValue: R|SomeEnum|, kClasses: R|kotlin/Array<out kotlin/reflect/KClass<*>>|, annotation: R|MyOtherAnnotation|): R|MyAnnotation| {
super<R|kotlin/Any|>()
}
public final val intValue: R|kotlin/Int| = R|<local>/intValue|
public get(): R|kotlin/Int|
public final val stringValue: R|kotlin/String| = R|<local>/stringValue|
public get(): R|kotlin/String|
public final val enumValue: R|SomeEnum| = R|<local>/enumValue|
public get(): R|SomeEnum|
public final val kClasses: R|kotlin/Array<out kotlin/reflect/KClass<*>>| = R|<local>/kClasses|
public get(): R|kotlin/Array<out kotlin/reflect/KClass<*>>|
public final val annotation: R|MyOtherAnnotation| = R|<local>/annotation|
public get(): R|MyOtherAnnotation|
}
public final annotation class MyOtherAnnotation : R|kotlin/Annotation| {
public constructor(intValue: R|kotlin/Int|, stringValue: R|kotlin/String|): R|MyOtherAnnotation| {
super<R|kotlin/Any|>()
}
public final val intValue: R|kotlin/Int| = R|<local>/intValue|
public get(): R|kotlin/Int|
public final val stringValue: R|kotlin/String| = R|<local>/stringValue|
public get(): R|kotlin/String|
}
public final const val constInt: R|kotlin/Int| = Int(10)
public get(): R|kotlin/Int|
public final const val constString: R|kotlin/String| = String()
public get(): R|kotlin/String|
@R|MyAnnotation|(intValue = Int(10), stringValue = R|/constString|, enumValue = Q|SomeEnum|.R|/SomeEnum.A|, kClasses = <implicitArrayOf>(<getClass>(Q|kotlin/String|), <getClass>(R|/constString|)), annotation = R|/MyOtherAnnotation.MyOtherAnnotation|(intValue = R|/constInt|, stringValue = String(hello))) public final fun foo(): R|kotlin/Unit| {
}

View File

@@ -0,0 +1,30 @@
import kotlin.reflect.KClass
enum class SomeEnum {
A, B
}
annotation class MyAnnotation(
val intValue: Int,
val stringValue: String,
val enumValue: SomeEnum,
val kClasses: Array<out KClass<*>>,
val annotation: MyOtherAnnotation
)
annotation class MyOtherAnnotation(val intValue: Int, val stringValue: String)
const val constInt = 10
const val constString = ""
@MyAnnotation(
intValue = 10,
stringValue = constString,
enumValue = SomeEnum.A,
kClasses = [String::class, <!ANNOTATION_ARGUMENT_MUST_BE_KCLASS_LITERAL!>constString::class<!>],
annotation = MyOtherAnnotation(
intValue = constInt,
stringValue = "hello"
)
)
fun foo() {}

View File

@@ -13,12 +13,12 @@ FILE: cast.kt
}
public get(): R|() -> kotlin/Unit|
public final val h: R|(kotlin/String) -> kotlin/Boolean| = fun <anonymous>(_: R|kotlin/String|): R|kotlin/Boolean| <inline=Unknown> {
public final val h: R|(kotlin/String) -> kotlin/Boolean| = fun <anonymous>(<unused var>: R|kotlin/String|): R|kotlin/Boolean| <inline=Unknown> {
^ Boolean(false)
}
public get(): R|(kotlin/String) -> kotlin/Boolean|
public final val hError: R|(ERROR CLASS: No type for parameter) -> kotlin/Boolean| = fun <anonymous>(_: <ERROR TYPE REF: No type for parameter>): R|kotlin/Boolean| <inline=Unknown> {
public final val hError: R|(ERROR CLASS: No type for parameter) -> kotlin/Boolean| = fun <anonymous>(<unused var>: <ERROR TYPE REF: No type for parameter>): R|kotlin/Boolean| <inline=Unknown> {
^ Boolean(true)
}

View File

@@ -0,0 +1,59 @@
digraph classCallInLambda_kt {
graph [nodesep=3]
node [shape=box penwidth=2]
edge [penwidth=2]
subgraph cluster_0 {
color=red
0 [label="Enter function test" style="filled" fillcolor=red];
subgraph cluster_1 {
color=blue
1 [label="Enter block"];
2 [label="Access variable R|<local>/x|"];
3 [label="Postponed enter to lambda"];
subgraph cluster_2 {
color=blue
11 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
subgraph cluster_3 {
color=blue
12 [label="Enter block"];
13 [label="Access variable R|<local>/it|"];
14 [label="::class call"];
15 [label="Exit block"];
}
16 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
}
4 [label="Call arguments union" style="filled" fillcolor=yellow];
5 [label="Postponed exit from lambda"];
6 [label="Function call: R|<local>/x|.R|kotlin/let|<R|kotlin/String|, R|kotlin/reflect/KClass<out kotlin/String>|>(...)"];
7 [label="Jump: ^test R|<local>/x|.R|kotlin/let|<R|kotlin/String|, R|kotlin/reflect/KClass<out kotlin/String>|>(<L> = let@fun <anonymous>(it: R|kotlin/String|): R|kotlin/reflect/KClass<out kotlin/String>| <inline=Inline, kind=EXACTLY_ONCE> {
^ <getClass>(R|<local>/it|)
}
)"];
8 [label="Stub" style="filled" fillcolor=gray];
9 [label="Exit block" style="filled" fillcolor=gray];
}
10 [label="Exit function test" style="filled" fillcolor=red];
}
0 -> {1};
1 -> {2};
2 -> {3};
3 -> {11};
3 -> {5} [color=red];
3 -> {11} [style=dashed];
4 -> {6} [color=red];
5 -> {6} [color=green];
6 -> {7};
7 -> {10};
7 -> {8} [style=dotted];
8 -> {9} [style=dotted];
9 -> {10} [style=dotted];
11 -> {12};
12 -> {13};
13 -> {14};
14 -> {15};
15 -> {16};
16 -> {4} [color=red];
16 -> {5} [color=green];
}

View File

@@ -0,0 +1,7 @@
FILE: classCallInLambda.kt
public final fun test(x: R|kotlin/String|): R|kotlin/reflect/KClass<*>| {
^test R|<local>/x|.R|kotlin/let|<R|kotlin/String|, R|kotlin/reflect/KClass<out kotlin/String>|>(<L> = let@fun <anonymous>(it: R|kotlin/String|): R|kotlin/reflect/KClass<out kotlin/String>| <inline=Inline, kind=EXACTLY_ONCE> {
^ <getClass>(R|<local>/it|)
}
)
}

View File

@@ -0,0 +1,7 @@
// WITH_STDLIB
// DUMP_CFG
import kotlin.reflect.KClass
fun test(x: String): KClass<*> {
return x.let { it::class }
}

View File

@@ -20,7 +20,7 @@ abstract class K {
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>abstract<!> val i2: Int
}
private open <!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER!>class L<!> : K()
private open <!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_ERROR!>class L<!> : K()
private abstract class M : K()
class X {

View File

@@ -66,3 +66,9 @@ class Test8<S8 : Test7<S8, <!UPPER_BOUND_VIOLATED!>in Any<!>>>
class Class<V : Any>
typealias Alias <V1> = (Class<V1>) -> Boolean
/* TODO: Should not be errors. Uncomment after fixing of https://youtrack.jetbrains.com/issue/KT-48044
abstract class Base<T : Base<T>> {}
class DerivedOut<out O : Base<out O>> {}
class DerivedIn<in I : Base<in I>> {}*/

View File

@@ -32,7 +32,7 @@ FILE: threeReceivers.kt
}
public final fun R|FooBar|.chk(buz: R|Buz|): R|kotlin/Unit| {
R|<local>/buz|.<Unresolved name: foobar>#()
R|<local>/buz|.<Expression 'foobar' of type 'Bar' cannot be invoked as a function>#()
}
}

View File

@@ -17,6 +17,6 @@ class Foo {
// this@Foo is dispatch receiver of foobar
// Foo/foobar is dispatch receiver of invoke
// this@chk is extension receiver of invoke
buz.<!UNRESOLVED_REFERENCE!>foobar<!>()
buz.<!FUNCTION_EXPECTED!>foobar<!>()
}
}

View File

@@ -41,7 +41,7 @@ FILE: inner.kt
public final fun test(): R|kotlin/Unit| {
lval o: R|Owner| = R|/Owner.Owner|()
R|<local>/o|.R|/Owner.foo|()
lval err: <ERROR TYPE REF: Unresolved name: Inner> = Q|Owner|.<Unresolved name: Inner>#()
lval err: <ERROR TYPE REF: Resolution to classifier> = Q|Owner|.<Resolution to classifier>#()
R|<local>/err|.<Unresolved name: baz>#()
lval i: R|Owner.Inner| = R|<local>/o|.R|/Owner.Inner.Inner|()
R|<local>/i|.R|/Owner.Inner.gau|()

View File

@@ -31,7 +31,7 @@ class Owner {
fun test() {
val o = Owner()
o.foo()
val err = Owner.<!UNRESOLVED_REFERENCE!>Inner<!>()
val err = Owner.<!RESOLUTION_TO_CLASSIFIER!>Inner<!>()
err.<!UNRESOLVED_REFERENCE!>baz<!>()
val i = o.Inner()
i.gau()

View File

@@ -0,0 +1,27 @@
FILE: anonymousInAnonymous.kt
public final fun foo(): R|kotlin/Unit| {
lval base: R|<anonymous>| = object : R|kotlin/Any| {
private constructor(): R|<anonymous>| {
super<R|kotlin/Any|>()
}
public final fun bar(): R|<anonymous>| {
^bar object : R|kotlin/Any| {
private constructor(): R|<anonymous>| {
super<R|kotlin/Any|>()
}
public final fun buz(): R|kotlin/String| {
^buz this@R|/<anonymous>|.R|/<anonymous>.foobar|
}
}
}
public final val foobar: R|kotlin/String| = String()
public get(): R|kotlin/String|
}
}

View File

@@ -0,0 +1,8 @@
fun foo() {
val base = object {
fun bar() = object {
fun buz() = foobar
}
val foobar = ""
}
}

View File

@@ -28,5 +28,5 @@ FILE: test.kt
lval res1: R|kotlin/String| = R|<local>/descriptor|.R|/WrappedPropertyDescriptor.setter|
lval res2: <ERROR TYPE REF: Unresolved name: getSetter> = R|<local>/descriptor|.<Unresolved name: getSetter>#()
lval res3: R|kotlin/Boolean| = R|<local>/descriptor|.R|/WrappedPropertyDescriptor.isDelegated|
lval res4: <ERROR TYPE REF: Unresolved name: isDelegated> = R|<local>/descriptor|.<Unresolved name: isDelegated>#()
lval res4: <ERROR TYPE REF: Expression 'isDelegated' of type 'kotlin/Boolean' cannot be invoked as a function> = R|<local>/descriptor|.<Expression 'isDelegated' of type 'kotlin/Boolean' cannot be invoked as a function>#()
}

View File

@@ -22,5 +22,5 @@ fun test() {
val res1 = descriptor.setter
val res2 = descriptor.<!UNRESOLVED_REFERENCE!>getSetter<!>() // Should be error
val res3 = descriptor.isDelegated
val res4 = descriptor.<!UNRESOLVED_REFERENCE!>isDelegated<!>() // Should be error
val res4 = descriptor.<!FUNCTION_EXPECTED!>isDelegated<!>() // Should be error
}

View File

@@ -1,5 +1,5 @@
FILE: main.kt
public final fun test(ann: R|Ann|): R|kotlin/Unit| {
R|<local>/ann|.R|/Ann.value|
R|<local>/ann|.<Unresolved name: value>#()
R|<local>/ann|.<Expression 'value' of type 'kotlin/String' cannot be invoked as a function>#()
}

View File

@@ -3,12 +3,12 @@
// FILE: Ann.java
public @interface Ann {
String value()
String value();
}
// FILE: main.kt
fun test(ann: Ann) {
ann.value
ann.<!UNRESOLVED_REFERENCE!>value<!>() // should be an error
ann.<!FUNCTION_EXPECTED!>value<!>() // should be an error
}

View File

@@ -1413,4 +1413,59 @@ digraph nullability_kt {
534 -> {535};
535 -> {536};
subgraph cluster_107 {
color=red
537 [label="Enter function test_14" style="filled" fillcolor=red];
subgraph cluster_108 {
color=blue
538 [label="Enter block"];
subgraph cluster_109 {
color=blue
539 [label="Enter when"];
subgraph cluster_110 {
color=blue
540 [label="Enter when branch condition "];
541 [label="Access variable R|<local>/q|"];
542 [label="Access variable R|/Q.data|"];
543 [label="Const: Null(null)"];
544 [label="Equality operator =="];
545 [label="Exit when branch condition"];
}
546 [label="Synthetic else branch"];
547 [label="Enter when branch result"];
subgraph cluster_111 {
color=blue
548 [label="Enter block"];
549 [label="Access variable R|<local>/q|"];
550 [label="Access variable R|/Q.data|"];
551 [label="Access variable <Inapplicable(UNSAFE_CALL): /MyData.s>#"];
552 [label="Exit block"];
}
553 [label="Exit when branch result"];
554 [label="Exit when"];
}
555 [label="Exit block"];
}
556 [label="Exit function test_14" style="filled" fillcolor=red];
}
537 -> {538};
538 -> {539};
539 -> {540};
540 -> {541};
541 -> {542};
542 -> {543};
543 -> {544};
544 -> {545};
545 -> {547 546};
546 -> {554};
547 -> {548};
548 -> {549};
549 -> {550};
550 -> {551};
551 -> {552};
552 -> {553};
553 -> {554};
554 -> {555};
555 -> {556};
}

View File

@@ -232,3 +232,11 @@ FILE: nullability.kt
}
}
public final fun test_14(q: R|Q|): R|kotlin/Unit| {
when () {
==(R|<local>/q|.R|/Q.data|, Null(null)) -> {
R|<local>/q|.R|/Q.data|.<Inapplicable(UNSAFE_CALL): /MyData.s>#
}
}
}

View File

@@ -175,3 +175,10 @@ fun test_13(q: QImplMutable?) {
<!SMARTCAST_IMPOSSIBLE!>q.data<!>.s.inc() // should be bad
}
}
fun test_14(q: Q) {
// `q.data` is a property that has an open getter
if (q.data == null) {
q.data<!UNSAFE_CALL!>.<!>s // should be UNSAFE_CALL and NOT SMARTCAST_IMPOSSIBLE
}
}

View File

@@ -7,7 +7,7 @@ interface FirFunctionCall : FirBase
fun foo(statements: List<FirBase>, arguments: List<FirBase>, explicitReceiver: FirBase): List<FirFunctionCall> {
val firstCalls = with(statements.last() as FirFunctionCall) setCall@{
buildList {
<!EXPERIMENTAL_API_USAGE_ERROR!>buildList<!> {
add(this@setCall)
with(arguments.last() as FirFunctionCall) plusCall@{
add(this@plusCall)

View File

@@ -19,7 +19,7 @@ FILE: delegateTypeMismatch.kt
public get(): R|kotlin/Boolean|
private final fun <T> property(initialValue: R|T|): R|kotlin/properties/ReadWriteProperty<A, T>| {
^property Q|kotlin/properties/Delegates|.R|kotlin/properties/Delegates.vetoable|<R|T|>(R|<local>/initialValue|, <L> = vetoable@fun <anonymous>(_: R|@R|kotlin/ParameterName|(name = String(property)) kotlin/reflect/KProperty<*>|, _: R|T|, _: R|T|): R|kotlin/Boolean| <inline=CrossInline, kind=UNKNOWN> {
^property Q|kotlin/properties/Delegates|.R|kotlin/properties/Delegates.vetoable|<R|T|>(R|<local>/initialValue|, <L> = vetoable@fun <anonymous>(<unused var>: R|@R|kotlin/ParameterName|(name = String(property)) kotlin/reflect/KProperty<*>|, <unused var>: R|T|, <unused var>: R|T|): R|kotlin/Boolean| <inline=CrossInline, kind=UNKNOWN> {
^ when () {
this@R|/A|.R|/A.isLocked| -> {
throw R|java/lang/IllegalStateException.IllegalStateException|(String(Cannot modify readonly DescriptorRendererOptions))

View File

@@ -1,4 +1,4 @@
fun <T> foo(@BuilderInference block: MutableList<T>.() -> Unit): T = null!!
fun <T> foo(@<!EXPERIMENTAL_API_USAGE_ERROR!>BuilderInference<!> block: MutableList<T>.() -> Unit): T = null!!
fun takeString(s: String) {}

View File

@@ -2,7 +2,7 @@ class DropDownComponent<T : Any>(val initialValues: List<T>)
fun test(strings: List<String>) {
val dropDown = DropDownComponent(
initialValues = buildList {
initialValues = <!EXPERIMENTAL_API_USAGE_ERROR!>buildList<!> {
addAll(strings)
}
)

View File

@@ -1,5 +1,5 @@
fun test_1() {
val list = buildList {
val list = <!EXPERIMENTAL_API_USAGE_ERROR!>buildList<!> {
add("")
}
takeList(list)
@@ -12,7 +12,7 @@ fun test_2() {
takeList(list)
}
fun <E> myBuildList(@BuilderInference builderAction: MutableList<E>.() -> Unit): List<E> {
fun <E> myBuildList(@<!EXPERIMENTAL_API_USAGE_ERROR!>BuilderInference<!> builderAction: MutableList<E>.() -> Unit): List<E> {
return ArrayList<E>().apply(builderAction)
}

View File

@@ -0,0 +1,3 @@
FILE: jvm.kt
@R|some/Nls|(R|some/Nls.Capitalization.Title|) public final fun f(): R|kotlin/Unit| {
}

Some files were not shown because too many files have changed in this diff Show More