Optimization in 2439c22ff6 introduced an array `absentArguments` with
default values of all parameter types, which is copied in `callBy`
instead of being recomputed each time. Unfortunately, its size was
computed incorrectly: `maskSize` should only take into account
value parameters (see the `parameter.kind == KParameter.Kind.VALUE`
check in `callBy`).
This led to an issue where if the function had 32 * N value parameters
and 1 receiver parameter, `maskSize` was greater by 1 than expected,
which caused an exception due to mismatching argument array sizes.
#KT-61304 Fixed
... as well as $SwitchMap and other synthetic classes generated by javac
or other JVM language compilers or runtimes.
Note that for Kotlin, all synthetic classes were already handled by the
subsequent check for `KotlinClassHeader.Kind.SYNTHETIC_CLASS`, but after
this change we won't call `ReflectKotlinClass.create` for those, which
is a minor optimization.
#KT-41373 Fixed
... for Kotlin-generated classes which do not correspond to a "class"
from the Kotlin language's point of view. For example, Kotlin lambdas,
file facade classes, multifile class facade/part classes, WhenMappings,
DefaultImpls. They can be distinguished from normal classes by the value
of `KotlinClassHeader.Kind` (which is the same as `Metadata.kind`).
Another theoretical option would be to throw exception at the point
where the `::class` expression is used, if the expression's type on the
left-hand side is a synthetic class. But we can't really do that since
it'll affect performance of most `<expression>::class` expressions.
So, construct a fake synthetic class instead, without any members except
equals/hashCode/toString, and without any non-trivial modifiers. It kind
of contradicts the general idea that kotlin-reflect presents anything
exactly the same as the compiler sees it, but arguably it's worth it to
avoid unexpected exceptions like in KT-41373.
In the newly added test, Java lambda check is muted but it should work
exactly the same as for Kotlin lambdas and other synthetic classes. It's
fixed in a subsequent commit.
#KT-41373 In Progress
Local classes and anonymous objects are normal classes and
kotlin-reflect can load all declarations and modifiers from them, and
support calling members, exactly in the same way as it does for normal
non-local classes.
#KT-41373 In Progress
There's no point in using `ReflectProperties.lazy` over
`lazy(PUBLICATION)`, especially because of the subtle problems the
former can create, such as KT-27585. This is inspired by the fix in
99b38ccb74, although in this case I couldn't come up with an example
that would lead to a runtime exception.
Root cause:
Cached in ClassValue values are prohibited to reference any java.lang.Class or ClassValue instances as they are considered as strong roots that prevent Class and ClassValue garbage collection,
creating effectively unloadable cycle.
This problem is also known as JDK-8136353.
Actions taken:
* Extract anonymous ClassValue instance into a separate static class that does not capture anything implicitly
* Wrap cached values in ClassValue into SoftReference to avoid unloadable cycles
^KT-56093 Fixed
Using `ReflectionProperties.lazy` is incorrect because it allows several
threads to observe different resulting values if they're computing it
simultaneously (unlike `lazy(PUBLICATION)`, which always returns the
value that "won the race").
In the case of property delegates, for example, if we're invoking
`isAccessible = true` and then `getDelegate()` concurrently, it might
happen that when some thread invokes `getDelegate()`, it gets the
underlying Field object which was written by another thread and which
has not yet been made accessible, leading to
IllegalPropertyDelegateAccessException.
#KT-27585 Fixed
- Make the implementations very similar, to fix KT-54833 where the
companion object case was forgotten for kotlinProperty.
- Optimize both functions to look up the function/property by name
first, to cover the most probable case when the JVM name of a
declaration is equal to its Kotlin name. This fixes KT-55937.
#KT-54833 Fixed
#KT-55937 Fixed
Since KT-53308, we started to cache results of typeOf invocation
in reflection. The cache uses the origin 'KClassifier' as a key with
an optional list of 'KTypeProjection' in type argument position,
and computed result as a value.
Without classifier check, the caching produces incorrect execution in
a very specific classloaders usage which is leveraged
by IDEA source-tree:
* All Kotlin stdlib and reflect classes are always loaded by the same
classloader
* Other classes that depend on Kotlin are loaded by separate
classloaders
The reproducer:
* Attempt to use typeOf<kotlin.List<Foo>> from one classloader caches
the resulting KType
* Attempt to use typeOf<kotlin.List<Foo>> from another classloader
for the same 'Foo' that differs only in classloader reuses the
computed KType, meaning that KType type argument classifier
is simply incorrect and points to the 'Foo' from the first classloader
#KT-54611 Fixed
#KT-54629 Fixed
Merge-request: KT-MR-7470
Merged-by: Vsevolod Tolstopyatov <qwwdfsad@gmail.com>
This is related to 8308f5d7d3 (KT-44977).
It turns out that it's necessary to create `ArrayValue` with a
precomputed type not only in case of annotations stored directly in
Kotlin metadata (i.e. annotations on types and type parameters), but
also for arguments of repeated annotations. The reason is that repeated
annotations are stored in an array themselves, as an argument to another
(container) annotation. The annotation-reading code unwraps this array
to load repeated annotations as individual instances of
`AnnotationDescriptor`, but in contrast to loading normal annotations,
it doesn't set `source` to the reflection object, it uses `NO_SOURCE`
(see BinaryClassAnnotationAndConstantLoaderImpl.AbstractAnnotationArgumentVisitor.visitArray).
So when kotlin-reflect is later asked for the arguments of the
annotation, it needs to recreate the reflection object from
`AnnotationDescriptor` in `util.kt`. Doing so requires knowing the array
type, which is now present because we're creating a `TypedArrayValue`
(previously `DeserializedArrayValue`) in places where arrays are read as
annotation arguments.
Alternative solution would be to fix source passed to
`AnnotationDescriptorImpl` in the annotation-reading code, but that
seems a bit messy because the code is very abstract and is used in lots
of other places.
#KT-53279 Fixed
* Cache KType instances constructor from the given classifier
* For generics, cache KTypes with already substituted arguments
* It significantly speeds up all typeOf-based APIs, both accesses to typeOf and its related properties (i.e. classifier)
#KT-53508
Merge-request: KT-MR-6818
Merged-by: Vsevolod Tolstopyatov <qwwdfsad@gmail.com>
* It is a heavy-weight object that is hard to compute
* It is being constructed each type _cached_ method ref is used in equals/hashCode
* Module name is deliberately ignored, corresponding doc is added where appropriate
#KT-48136
Merge-request: KT-MR-6817
Merged-by: Vsevolod Tolstopyatov <qwwdfsad@gmail.com>
* Replace pcollections with ClassValue/ConcurrentHashMap-based caches
* Do not store weak references, instead cache strong references and count on ClassValue to unload the corresponding classloader if necessary
* ConcurrentHashMap does not rely on WeakReference as it's only selected on Android where classloader leaks don't exist
* Update reflect/scripting JDK requirement to Java 8 in order to proceed
#KT-53454
#KT-50705
Merge-request: KT-MR-6788
Merged-by: Vsevolod Tolstopyatov <qwwdfsad@gmail.com>
The proper support will come in KT-15518, but that would be a breaking
change even for stable Kotlin without kotlin-reflect. Before that issue
is fixed, represent Nothing in types with the Void class, and use a flag
in the no-reflect implementation to remember that it's not actually the
Void class itself.
#KT-39166 Fixed
This function was always experimental, as explained in its kdoc, but it
was introduced before opt-in requirement markers were supported. Thus,
breaking changes (such as in KT-42746) were always expected, and the
`@ExperimentalReflectionOnLambdas` annotation just makes it clearer.
#KT-45486 Fixed
Although the previous code of computing JVM internal name from a Class
instance was shorter, it led to unnecessary creation of array types,
which is less performant and makes configuration of kotlin-reflect for
GraalVM native-image more verbose.
Unfortunately I didn't succeed in writing a test for this, since
`Array.newInstance` calls a native method which doesn't record any trace
of it being called in the class loader: the resulting array type never
goes through findClass/loadClass, and is not visible via
findLoadedClass.
#KT-44594 Fixed