Extract reflection implementation to module runtime.jvm

This commit is contained in:
Alexander Udalov
2014-11-07 20:08:38 +03:00
parent 4f0d83a7fe
commit 57d37a3860
29 changed files with 33 additions and 12 deletions
@@ -1,31 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect
suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
public class IllegalAccessException(cause: java.lang.IllegalAccessException) : Exception() {
{
(this as java.lang.Throwable).initCause(cause)
}
}
suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
public class NoSuchPropertyException(cause: Exception) : Exception() {
{
(this as java.lang.Throwable).initCause(cause)
}
}
@@ -1,21 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal
import kotlin.reflect.KCallable
trait KCallableImpl<out R> : KCallable<R>
@@ -1,70 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal
import kotlin.reflect.*
import kotlin.jvm.internal.KotlinClass
import kotlin.jvm.internal.KotlinSyntheticClass
enum class KClassOrigin {
BUILT_IN
KOTLIN
FOREIGN
}
private val KOTLIN_CLASS_ANNOTATION_CLASS = javaClass<KotlinClass>()
private val KOTLIN_SYNTHETIC_CLASS_ANNOTATION_CLASS = javaClass<KotlinSyntheticClass>()
class KClassImpl<out T>(val jClass: Class<T>, isKnownToBeKotlin: Boolean) : KClass<T> {
// TODO: write metadata to local classes
private val origin: KClassOrigin =
if (isKnownToBeKotlin ||
jClass.isAnnotationPresent(KOTLIN_CLASS_ANNOTATION_CLASS) ||
jClass.isAnnotationPresent(KOTLIN_SYNTHETIC_CLASS_ANNOTATION_CLASS)
) {
KClassOrigin.KOTLIN
}
else {
KClassOrigin.FOREIGN
// TODO: built-in classes
}
fun memberProperty(name: String): KMemberProperty<T, *> =
if (origin identityEquals KClassOrigin.KOTLIN) {
KMemberPropertyImpl<T, Any>(name, this)
}
else {
KForeignMemberProperty<T, Any>(name, this)
}
fun mutableMemberProperty(name: String): KMutableMemberProperty<T, *> =
if (origin identityEquals KClassOrigin.KOTLIN) {
KMutableMemberPropertyImpl<T, Any>(name, this)
}
else {
KMutableForeignMemberProperty<T, Any>(name, this)
}
override fun equals(other: Any?): Boolean =
other is KClassImpl<*> && jClass == other.jClass
override fun hashCode(): Int =
jClass.hashCode()
override fun toString(): String =
jClass.toString()
}
@@ -1,21 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal
import kotlin.jvm.internal.ExtensionFunctionImpl
public abstract class KExtensionFunctionImpl<in T, out R> : ExtensionFunctionImpl<T, R>()
@@ -1,72 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal
import java.lang.reflect.*
import kotlin.reflect.*
open class KForeignMemberProperty<T : Any, out R>(
override val name: String,
protected val owner: KClassImpl<T>
) : KMemberProperty<T, R>, KPropertyImpl<R> {
override val field: Field = try {
owner.jClass.getField(name)
}
catch (e: NoSuchFieldException) {
throw NoSuchPropertyException(e)
}
override val getter: Method? get() = null
override fun get(receiver: T): R {
try {
return field.get(receiver) as R
}
catch (e: java.lang.IllegalAccessException) {
throw kotlin.reflect.IllegalAccessException(e)
}
}
override fun equals(other: Any?): Boolean =
other is KForeignMemberProperty<*, *> && name == other.name && owner == other.owner
override fun hashCode(): Int =
name.hashCode() * 31 + owner.hashCode()
// TODO: include visibility, return type
override fun toString(): String =
"val ${owner.jClass.getName()}.$name"
}
class KMutableForeignMemberProperty<T : Any, out R>(
name: String,
owner: KClassImpl<T>
) : KMutableMemberProperty<T, R>, KMutablePropertyImpl<R>, KForeignMemberProperty<T, R>(name, owner) {
override val setter: Method? get() = null
override fun set(receiver: T, value: R) {
try {
field.set(receiver, value)
}
catch (e: java.lang.IllegalAccessException) {
throw kotlin.reflect.IllegalAccessException(e)
}
}
override fun toString(): String =
"var ${owner.jClass.getName()}.$name"
}
@@ -1,21 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal
import kotlin.jvm.internal.FunctionImpl
public abstract class KFunctionImpl<out R> : FunctionImpl<R>()
@@ -1,23 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal
import java.io.Serializable
public abstract class KMemberFunctionImpl<in T, out R> : Serializable {
override fun toString() = "${(this as Object).getClass().getGenericInterfaces()[0]}"
}
@@ -1,97 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal
import java.lang.reflect.*
import kotlin.reflect.*
// TODO: properties of built-in classes
open class KMemberPropertyImpl<T : Any, out R>(
override val name: String,
protected val owner: KClassImpl<T>
) : KMemberProperty<T, R>, KPropertyImpl<R> {
// TODO: extract, make lazy (weak?), use our descriptors knowledge
override val field: Field?
override val getter: Method?
{
try {
field = owner.jClass.getDeclaredField(name)
}
catch (e: NoSuchFieldException) {
field = null
}
try {
getter = owner.jClass.getMaybeDeclaredMethod(getterName(name))
}
catch (e: NoSuchMethodException) {
if (field == null) throw NoSuchPropertyException(e)
getter = null
}
}
override fun get(receiver: T): R {
try {
return (if (getter != null) getter!!(receiver) else field!!.get(receiver)) as R
}
catch (e: java.lang.IllegalAccessException) {
throw kotlin.reflect.IllegalAccessException(e)
}
}
override fun equals(other: Any?): Boolean =
other is KMemberPropertyImpl<*, *> && name == other.name && owner == other.owner
override fun hashCode(): Int =
name.hashCode() * 31 + owner.hashCode()
// TODO: include visibility, return type
override fun toString(): String =
"val ${owner.jClass.getName()}.$name"
}
class KMutableMemberPropertyImpl<T : Any, R>(
name: String,
owner: KClassImpl<T>
) : KMutableMemberProperty<T, R>, KMutablePropertyImpl<R>, KMemberPropertyImpl<T, R>(name, owner) {
override val setter: Method?
{
try {
val returnType = if (getter != null) getter.getReturnType() else field!!.getType()
setter = owner.jClass.getMaybeDeclaredMethod(setterName(name), returnType!!)
}
catch (e: NoSuchMethodException) {
if (field == null) throw NoSuchPropertyException(e)
setter = null
}
}
override fun set(receiver: T, value: R) {
try {
if (setter != null) setter!!(receiver, value) else field!!.set(receiver, value)
}
catch (e: java.lang.IllegalAccessException) {
throw kotlin.reflect.IllegalAccessException(e)
}
}
override fun toString(): String =
"var ${owner.jClass.getName()}.$name"
}
@@ -1,49 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal
import kotlin.reflect.KPackage
import kotlin.jvm.internal.KotlinPackage
private val KOTLIN_PACKAGE_ANNOTATION_CLASS = javaClass<KotlinPackage>()
class KPackageImpl(val jClass: Class<*>) : KPackage {
override fun equals(other: Any?): Boolean =
other is KPackageImpl && jClass == other.jClass
override fun hashCode(): Int =
jClass.hashCode()
suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
override fun toString(): String {
val name = jClass.getName() as java.lang.String
return if (jClass.isAnnotationPresent(KOTLIN_PACKAGE_ANNOTATION_CLASS)) {
// Cast to Any is needed to suppress the error: "Operator '==' cannot be applied to 'java.lang.String' and 'kotlin.String'"
if ((name : Any) == "_DefaultPackage") {
"package <default>"
}
else {
val lastDot = name.lastIndexOf(".")
if (lastDot >= 0) {
"package ${name.substring(0, lastDot)}"
}
else "package $name"
}
}
else "package $name"
}
}
@@ -1,31 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal
import java.lang.reflect.*
import kotlin.reflect.*
trait KPropertyImpl<out R> : KProperty<R>, KCallableImpl<R> {
val field: Field?
val getter: Method?
}
trait KMutablePropertyImpl<R> : KMutableProperty<R>, KPropertyImpl<R> {
val setter: Method?
}
@@ -1,113 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal
import java.lang.reflect.*
import kotlin.reflect.*
open class KTopLevelExtensionPropertyImpl<T, out R>(
override val name: String,
protected val owner: KPackageImpl,
protected val receiverClass: Class<T>
) : KTopLevelExtensionProperty<T, R>, KPropertyImpl<R> {
override val field: Field? get() = null
// TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields
override val getter: Method = try {
owner.jClass.getMethod(getterName(name), receiverClass)
}
catch (e: NoSuchMethodException) {
throw NoSuchPropertyException(e)
}
override fun get(receiver: T): R {
try {
return getter(null, receiver) as R
}
catch (e: java.lang.IllegalAccessException) {
throw kotlin.reflect.IllegalAccessException(e)
}
}
override fun equals(other: Any?): Boolean =
other is KTopLevelExtensionPropertyImpl<*, *> && name == other.name && owner == other.owner && receiverClass == other.receiverClass
override fun hashCode(): Int =
(name.hashCode() * 31 + owner.hashCode()) * 31 + receiverClass.hashCode()
// TODO: include visibility, return type, maybe package
override fun toString(): String =
"val ${mapJavaClassToKotlin(receiverClass.getName())}.$name"
}
class KMutableTopLevelExtensionPropertyImpl<T, R>(
name: String,
owner: KPackageImpl,
receiverClass: Class<T>
) : KMutableTopLevelExtensionProperty<T, R>, KMutablePropertyImpl<R>, KTopLevelExtensionPropertyImpl<T, R>(name, owner, receiverClass) {
override val setter: Method = try {
owner.jClass.getMethod(setterName(name), receiverClass, getter.getReturnType()!!)
}
catch (e: NoSuchMethodException) {
throw NoSuchPropertyException(e)
}
override fun set(receiver: T, value: R) {
try {
setter.invoke(null, receiver, value)
}
catch (e: java.lang.IllegalAccessException) {
throw kotlin.reflect.IllegalAccessException(e)
}
}
override fun toString(): String =
"var ${mapJavaClassToKotlin(receiverClass.getName())}.$name"
}
suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
private fun mapJavaClassToKotlin(name: String): String {
if (Character.isLowerCase(name[0])) {
return when (name) {
"boolean" -> "kotlin.Boolean"
"char" -> "kotlin.Char"
"byte" -> "kotlin.Byte"
"short" -> "kotlin.Short"
"int" -> "kotlin.Int"
"float" -> "kotlin.Float"
"long" -> "kotlin.Long"
"double" -> "kotlin.Double"
else -> name
}
}
if (name[0] == '[') {
val element = (name as java.lang.String).substring(1)
return when (element[0]) {
'Z' -> "kotlin.BooleanArray"
'C' -> "kotlin.CharArray"
'B' -> "kotlin.ByteArray"
'S' -> "kotlin.ShortArray"
'I' -> "kotlin.IntArray"
'F' -> "kotlin.FloatArray"
'J' -> "kotlin.LongArray"
'D' -> "kotlin.DoubleArray"
'L' -> "kotlin.Array<${mapJavaClassToKotlin((element as java.lang.String).substring(1, element.length() - 1))}>"
else -> "kotlin.Array<${mapJavaClassToKotlin(element)}>"
}
}
return name
}
@@ -1,79 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal
import java.lang.reflect.*
import kotlin.reflect.*
open class KTopLevelVariableImpl<out R>(
override val name: String,
protected val owner: KPackageImpl
) : KTopLevelVariable<R>, KVariableImpl<R> {
// TODO: load the field from the corresponding package part
override val field: Field? get() = null
// TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields
override val getter: Method = try {
owner.jClass.getMethod(getterName(name))
}
catch (e: NoSuchMethodException) {
throw NoSuchPropertyException(e)
}
override fun get(): R {
try {
return getter(null) as R
}
catch (e: java.lang.IllegalAccessException) {
throw kotlin.reflect.IllegalAccessException(e)
}
}
override fun equals(other: Any?): Boolean =
other is KTopLevelVariableImpl<*> && name == other.name && owner == other.owner
override fun hashCode(): Int =
name.hashCode() * 31 + owner.hashCode()
// TODO: include visibility, return type, maybe package
override fun toString(): String =
"val $name"
}
class KMutableTopLevelVariableImpl<R>(
name: String,
owner: KPackageImpl
) : KMutableTopLevelVariable<R>, KMutableVariableImpl<R>, KTopLevelVariableImpl<R>(name, owner) {
override val setter: Method = try {
owner.jClass.getMethod(setterName(name), getter.getReturnType()!!)
}
catch (e: NoSuchMethodException) {
throw NoSuchPropertyException(e)
}
override fun set(value: R) {
try {
setter.invoke(null, value)
}
catch (e: java.lang.IllegalAccessException) {
throw kotlin.reflect.IllegalAccessException(e)
}
}
override fun toString(): String =
"var $name"
}
@@ -1,23 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal
import kotlin.reflect.*
trait KVariableImpl<out R> : KVariable<R>, KPropertyImpl<R>
trait KMutableVariableImpl<R> : KMutableVariable<R>, KVariableImpl<R>, KMutablePropertyImpl<R>
@@ -1,40 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal
import kotlin.reflect.*
fun <T> kClass(jClass: Class<T>): KClassImpl<T> =
KClassImpl<T>(jClass, false)
fun <T> kClassFromKotlin(jClass: Class<T>): KClassImpl<T> =
KClassImpl<T>(jClass, true)
fun kPackage(jClass: Class<*>): KPackageImpl =
KPackageImpl(jClass)
fun topLevelVariable(name: String, owner: KPackageImpl): KTopLevelVariableImpl<Any?> =
KTopLevelVariableImpl<Any?>(name, owner)
fun mutableTopLevelVariable(name: String, owner: KPackageImpl): KMutableTopLevelVariableImpl<Any?> =
KMutableTopLevelVariableImpl<Any?>(name, owner)
fun <T> topLevelExtensionProperty(name: String, owner: KPackageImpl, receiver: Class<T>): KTopLevelExtensionPropertyImpl<T, Any?> =
KTopLevelExtensionPropertyImpl<T, Any?>(name, owner, receiver)
fun <T> mutableTopLevelExtensionProperty(name: String, owner: KPackageImpl, receiver: Class<T>): KMutableTopLevelExtensionPropertyImpl<T, Any?> =
KMutableTopLevelExtensionPropertyImpl<T, Any?>(name, owner, receiver)
@@ -1,65 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal
import java.lang.ref.WeakReference
import kotlin.reflect.jvm.internal.pcollections.HashPMap
// TODO: collect nulls periodically
// Key of the map is Class.getName(), each value is either a WeakReference<KClassImpl<*>> or an Array<WeakReference<KClassImpl<*>>>.
// Arrays are needed because the same class can be loaded by different class loaders, which results in different Class instances.
// This variable is not volatile intentionally: we don't care if there's a data race on it and some KClass instances will be lost.
// We do care however about general performance on read access to it, thus no synchronization is done here whatsoever
private var FOREIGN_K_CLASSES = HashPMap.empty<String, Any>()
// This function is invoked on each reflection access to Java classes, properties, etc. Performance is critical here.
fun <T> foreignKotlinClass(jClass: Class<T>): KClassImpl<T> {
val name = jClass.getName()
val cached = FOREIGN_K_CLASSES[name]
if (cached is WeakReference<*>) {
val kClass = cached.get() as KClassImpl<T>?
if (kClass?.jClass == jClass) {
return kClass!!
}
}
else if (cached != null) {
// If the cached value is not a weak reference, it's an array of weak references
cached as Array<WeakReference<KClassImpl<T>>>
for (ref in cached) {
val kClass = ref.get()
if (kClass?.jClass == jClass) {
return kClass!!
}
}
// This is the most unlikely case: we found a cached array of references of length at least 2 (can't be 1 because
// the single element would be cached instead), and none of those classes is the one we're looking for
val size = cached.size
// Don't use Array constructor because it creates a lambda
val newArray = arrayOfNulls<WeakReference<KClassImpl<*>>>(size + 1)
// Don't use Arrays.copyOf because it works reflectively
System.arraycopy(cached, 0, newArray, 0, size)
val newKClass = kClass<T>(jClass)
newArray[size] = WeakReference(newKClass)
FOREIGN_K_CLASSES = FOREIGN_K_CLASSES.plus(name, newArray)
return newKClass
}
val newKClass = kClass<T>(jClass)
FOREIGN_K_CLASSES = FOREIGN_K_CLASSES.plus(name, WeakReference(newKClass))
return newKClass
}
@@ -1,118 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal.pcollections;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* A simple persistent stack of non-null values.
* <p/>
* This implementation is thread-safe, although its iterators may not be.
*/
final class ConsPStack<E> implements Iterable<E> {
private static final ConsPStack<Object> EMPTY = new ConsPStack<Object>();
@SuppressWarnings("unchecked")
public static <E> ConsPStack<E> empty() {
return (ConsPStack<E>) EMPTY;
}
private final E first;
private final ConsPStack<E> rest;
private final int size;
private ConsPStack() { // EMPTY constructor
size = 0;
first = null;
rest = null;
}
private ConsPStack(E first, ConsPStack<E> rest) {
this.first = first;
this.rest = rest;
this.size = 1 + rest.size;
}
public E get(int index) {
if (index < 0 || index > size) throw new IndexOutOfBoundsException();
try {
return iterator(index).next();
} catch (NoSuchElementException e) {
throw new IndexOutOfBoundsException("Index: " + index);
}
}
@Override
public Iterator<E> iterator() {
return iterator(0);
}
public int size() {
return size;
}
private Iterator<E> iterator(final int index) {
return new Iterator<E>() {
ConsPStack<E> next = subList(index);
@Override
public boolean hasNext() {
return next.size > 0;
}
@Override
public E next() {
E e = next.first;
next = next.rest;
return e;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public ConsPStack<E> plus(E e) {
return new ConsPStack<E>(e, this);
}
private ConsPStack<E> minus(Object e) {
if (size == 0) return this;
if (first.equals(e)) // found it
return rest; // don't recurse (only remove one)
// otherwise keep looking:
ConsPStack<E> newRest = rest.minus(e);
if (newRest == rest) return this;
return new ConsPStack<E>(first, newRest);
}
public ConsPStack<E> minus(int i) {
return minus(get(i));
}
private ConsPStack<E> subList(int start) {
if (start < 0 || start > size)
throw new IndexOutOfBoundsException();
if (start == 0)
return this;
return rest.subList(start - 1);
}
}
@@ -1,95 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal.pcollections;
import org.jetbrains.annotations.NotNull;
/**
* A persistent map from non-null keys to non-null values.
*/
public final class HashPMap<K, V> {
private static final HashPMap<Object, Object> EMPTY = new HashPMap<Object, Object>(IntTreePMap.<ConsPStack<MapEntry<Object, Object>>>empty(), 0);
@SuppressWarnings("unchecked")
@NotNull
public static <K, V> HashPMap<K, V> empty() {
return (HashPMap<K, V>) HashPMap.EMPTY;
}
private final IntTreePMap<ConsPStack<MapEntry<K, V>>> intMap;
private final int size;
private HashPMap(IntTreePMap<ConsPStack<MapEntry<K, V>>> intMap, int size) {
this.intMap = intMap;
this.size = size;
}
public int size() {
return size;
}
public boolean containsKey(Object key) {
return keyIndexIn(getEntries(key.hashCode()), key) != -1;
}
public V get(Object key) {
ConsPStack<MapEntry<K, V>> entries = getEntries(key.hashCode());
for (MapEntry<K, V> entry : entries)
if (entry.key.equals(key))
return entry.value;
return null;
}
@NotNull
public HashPMap<K, V> plus(K key, V value) {
ConsPStack<MapEntry<K, V>> entries = getEntries(key.hashCode());
int size0 = entries.size();
int i = keyIndexIn(entries, key);
if (i != -1) entries = entries.minus(i);
entries = entries.plus(new MapEntry<K, V>(key, value));
return new HashPMap<K, V>(intMap.plus(key.hashCode(), entries), size - size0 + entries.size());
}
@NotNull
public HashPMap<K, V> minus(Object key) {
ConsPStack<MapEntry<K, V>> entries = getEntries(key.hashCode());
int i = keyIndexIn(entries, key);
if (i == -1) // key not in this
return this;
entries = entries.minus(i);
if (entries.size() == 0) // get rid of the entire hash entry
return new HashPMap<K, V>(intMap.minus(key.hashCode()), size - 1);
// otherwise replace hash entry with new smaller one:
return new HashPMap<K, V>(intMap.plus(key.hashCode(), entries), size - 1);
}
private ConsPStack<MapEntry<K, V>> getEntries(int hash) {
ConsPStack<MapEntry<K, V>> entries = intMap.get(hash);
if (entries == null) return ConsPStack.empty();
return entries;
}
private static <K, V> int keyIndexIn(ConsPStack<MapEntry<K, V>> entries, Object key) {
int i = 0;
for (MapEntry<K, V> entry : entries) {
if (entry.key.equals(key))
return i;
i++;
}
return -1;
}
}
@@ -1,264 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal.pcollections;
/**
* A non-public utility class for persistent balanced tree maps with integer keys.
* <p/>
* To allow for efficiently increasing all keys above a certain value or decreasing
* all keys below a certain value, the keys values are stored relative to their parent.
* This makes this map a good backing for fast insertion and removal of indices in a
* vector.
* <p/>
* This implementation is thread-safe except for its iterators.
* <p/>
* Other than that, this tree is based on the Glasgow Haskell Compiler's Data.Map implementation,
* which in turn is based on "size balanced binary trees" as described by:
* <p/>
* Stephen Adams, "Efficient sets: a balancing act",
* Journal of Functional Programming 3(4):553-562, October 1993,
* http://www.swiss.ai.mit.edu/~adams/BB/.
* <p/>
* J. Nievergelt and E.M. Reingold, "Binary search trees of bounded balance",
* SIAM journal of computing 2(1), March 1973.
*
* @author harold
*/
final class IntTree<V> {
// marker value:
static final IntTree<Object> EMPTYNODE = new IntTree<Object>();
// we use longs so relative keys can express all ints
// (e.g. if this has key -10 and right has 'absolute' key MAXINT,
// then its relative key is MAXINT+10 which overflows)
// there might be some way to deal with this based on left-verse-right logic,
// but that sounds like a mess.
private final long key;
private final V value; // null value means this is empty node
private final IntTree<V> left, right;
private final int size;
private IntTree() {
size = 0;
key = 0;
value = null;
left = null;
right = null;
}
private IntTree(long key, V value, IntTree<V> left, IntTree<V> right) {
this.key = key;
this.value = value;
this.left = left;
this.right = right;
size = 1 + left.size + right.size;
}
private IntTree<V> withKey(long newKey) {
if (size == 0 || newKey == key) return this;
return new IntTree<V>(newKey, value, left, right);
}
boolean containsKey(long key) {
if (size == 0)
return false;
if (key < this.key)
return left.containsKey(key - this.key);
if (key > this.key)
return right.containsKey(key - this.key);
// otherwise key==this.key:
return true;
}
V get(long key) {
if (size == 0)
return null;
if (key < this.key)
return left.get(key - this.key);
if (key > this.key)
return right.get(key - this.key);
// otherwise key==this.key:
return value;
}
IntTree<V> plus(long key, V value) {
if (size == 0)
return new IntTree<V>(key, value, this, this);
if (key < this.key)
return rebalanced(left.plus(key - this.key, value), right);
if (key > this.key)
return rebalanced(left, right.plus(key - this.key, value));
// otherwise key==this.key, so we simply replace this, with no effect on balance:
if (value == this.value)
return this;
return new IntTree<V>(key, value, left, right);
}
IntTree<V> minus(long key) {
if (size == 0)
return this;
if (key < this.key)
return rebalanced(left.minus(key - this.key), right);
if (key > this.key)
return rebalanced(left, right.minus(key - this.key));
// otherwise key==this.key, so we are killing this node:
if (left.size == 0) // we can just become right node
// make key 'absolute':
return right.withKey(right.key + this.key);
if (right.size == 0) // we can just become left node
return left.withKey(left.key + this.key);
// otherwise replace this with the next key (i.e. the smallest key to the right):
// TODO have minNode() instead of minKey to avoid having to call get()
// TODO get node from larger subtree, i.e. if left.size>right.size use left.maxNode()
// TODO have faster minusMin() instead of just using minus()
long newKey = right.minKey() + this.key;
//(right.minKey() is relative to this; adding this.key makes it 'absolute'
// where 'absolute' really means relative to the parent of this)
V newValue = right.get(newKey - this.key);
// now that we've got the new stuff, take it out of the right subtree:
IntTree<V> newRight = right.minus(newKey - this.key);
// lastly, make the subtree keys relative to newKey (currently they are relative to this.key):
newRight = newRight.withKey((newRight.key + this.key) - newKey);
// left is definitely not empty:
IntTree<V> newLeft = left.withKey((left.key + this.key) - newKey);
return rebalanced(newKey, newValue, newLeft, newRight);
}
/**
* Changes every key k>=key to k+delta.
* <p/>
* This method will create an _invalid_ tree if delta<0
* and the distance between the smallest k>=key in this
* and the largest j<key in this is |delta| or less.
* <p/>
* In other words, this method must not result in any change
* in the order of the keys in this, since the tree structure is
* not being changed at all.
*/
IntTree<V> changeKeysAbove(long key, int delta) {
if (size == 0 || delta == 0)
return this;
if (this.key >= key)
// adding delta to this.key changes the keys of _all_ children of this,
// so we now need to un-change the children of this smaller than key,
// all of which are to the left. note that we still use the 'old' relative key...:
return new IntTree<V>(this.key + delta, value, left.changeKeysBelow(key - this.key, -delta), right);
// otherwise, doesn't apply yet, look to the right:
IntTree<V> newRight = right.changeKeysAbove(key - this.key, delta);
if (newRight == right) return this;
return new IntTree<V>(this.key, value, left, newRight);
}
/**
* Changes every key k<key to k+delta.
* <p/>
* This method will create an _invalid_ tree if delta>0
* and the distance between the largest k<key in this
* and the smallest j>=key in this is delta or less.
* <p/>
* In other words, this method must not result in any overlap or change
* in the order of the keys in this, since the tree _structure_ is
* not being changed at all.
*/
IntTree<V> changeKeysBelow(long key, int delta) {
if (size == 0 || delta == 0)
return this;
if (this.key < key)
// adding delta to this.key changes the keys of _all_ children of this,
// so we now need to un-change the children of this larger than key,
// all of which are to the right. note that we still use the 'old' relative key...:
return new IntTree<V>(this.key + delta, value, left, right.changeKeysAbove(key - this.key, -delta));
// otherwise, doesn't apply yet, look to the left:
IntTree<V> newLeft = left.changeKeysBelow(key - this.key, delta);
if (newLeft == left) return this;
return new IntTree<V>(this.key, value, newLeft, right);
}
// min key in this:
private long minKey() {
if (left.size == 0)
return key;
// make key 'absolute' (i.e. relative to the parent of this):
return left.minKey() + this.key;
}
private IntTree<V> rebalanced(IntTree<V> newLeft, IntTree<V> newRight) {
if (newLeft == left && newRight == right)
return this; // already balanced
return rebalanced(key, value, newLeft, newRight);
}
private static final int OMEGA = 5;
private static final int ALPHA = 2;
// rebalance a tree that is off-balance by at most 1:
private static <V> IntTree<V> rebalanced(long key, V value, IntTree<V> left, IntTree<V> right) {
if (left.size + right.size > 1) {
if (left.size >= OMEGA * right.size) { // rotate to the right
IntTree<V> ll = left.left, lr = left.right;
if (lr.size < ALPHA * ll.size) // single rotation
return new IntTree<V>(left.key + key, left.value,
ll,
new IntTree<V>(-left.key, value,
lr.withKey(lr.key + left.key),
right));
else { // double rotation:
IntTree<V> lrl = lr.left, lrr = lr.right;
return new IntTree<V>(lr.key + left.key + key, lr.value,
new IntTree<V>(-lr.key, left.value,
ll,
lrl.withKey(lrl.key + lr.key)),
new IntTree<V>(-left.key - lr.key, value,
lrr.withKey(lrr.key + lr.key + left.key),
right));
}
} else if (right.size >= OMEGA * left.size) { // rotate to the left
IntTree<V> rl = right.left, rr = right.right;
if (rl.size < ALPHA * rr.size) // single rotation
return new IntTree<V>(right.key + key, right.value,
new IntTree<V>(-right.key, value,
left,
rl.withKey(rl.key + right.key)),
rr);
else { // double rotation:
IntTree<V> rll = rl.left, rlr = rl.right;
return new IntTree<V>(rl.key + right.key + key, rl.value,
new IntTree<V>(-right.key - rl.key, value,
left,
rll.withKey(rll.key + rl.key + right.key)),
new IntTree<V>(-rl.key, right.value,
rlr.withKey(rlr.key + rl.key),
rr));
}
}
}
// otherwise already balanced enough:
return new IntTree<V>(key, value, left, right);
}
}
@@ -1,52 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal.pcollections;
/**
* An efficient persistent map from integer keys to non-null values.
*/
final class IntTreePMap<V> {
private static final IntTreePMap<Object> EMPTY = new IntTreePMap<Object>(IntTree.EMPTYNODE);
@SuppressWarnings("unchecked")
public static <V> IntTreePMap<V> empty() {
return (IntTreePMap<V>) EMPTY;
}
private final IntTree<V> root;
private IntTreePMap(IntTree<V> root) {
this.root = root;
}
private IntTreePMap<V> withRoot(IntTree<V> root) {
if (root == this.root) return this;
return new IntTreePMap<V>(root);
}
public V get(int key) {
return root.get(key);
}
public IntTreePMap<V> plus(int key, V value) {
return withRoot(root.plus(key, value));
}
public IntTreePMap<V> minus(int key) {
return withRoot(root.minus(key));
}
}
@@ -1,47 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal.pcollections;
final class MapEntry<K, V> implements java.io.Serializable {
private static final long serialVersionUID = 7138329143949025153L;
public final K key;
public final V value;
public MapEntry(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof MapEntry)) return false;
MapEntry<?, ?> e = (MapEntry<?, ?>) o;
return (key == null ? e.key == null : key.equals(e.key)) &&
(value == null ? e.value == null : value.equals(e.value));
}
@Override
public int hashCode() {
return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode());
}
@Override
public String toString() {
return key + "=" + value;
}
}
@@ -1,51 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm.internal
import java.lang.reflect.Method
import kotlin.jvm.internal.Intrinsic
// TODO: use stdlib?
suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
private fun String.capitalizeWithJavaBeanConvention(): String {
// The code is a bit crooked because otherwise there are overload resolution ambiguities caused by the fact
// that we compile it with the built-ins both in source and as a compiled library
val l = length
if (l > 1 && Character.isUpperCase(get(1))) return this
val first = get(0)
this as java.lang.String
return "" + Character.toUpperCase(first) + substring(1, l)
}
private fun getterName(propertyName: String): String = "get" + propertyName.capitalizeWithJavaBeanConvention()
private fun setterName(propertyName: String): String = "set" + propertyName.capitalizeWithJavaBeanConvention()
// A local copy of javaClass() from stdlib is needed because there's no dependency on stdlib in runtime.jvm
[Intrinsic("kotlin.javaClass.function")]
fun <reified T> javaClass(): Class<T> = throw UnsupportedOperationException()
private fun Class<*>.getMaybeDeclaredMethod(name: String, vararg parameterTypes: Class<*>): Method {
try {
return getMethod(name, *parameterTypes)
}
catch (e: NoSuchMethodException) {
// This is needed to support private methods
return getDeclaredMethod(name, *parameterTypes)
}
}
@@ -1,84 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm
import java.lang.reflect.*
import kotlin.reflect.*
import kotlin.reflect.jvm.internal.*
// Kotlin reflection -> Java reflection
public val <T> KClass<T>.java: Class<T>
get() = (this as KClassImpl<T>).jClass
public val KPackage.javaFacade: Class<*>
get() = (this as KPackageImpl).jClass
public val KProperty<*>.javaGetter: Method?
get() = (this as? KPropertyImpl<*>)?.getter
public val KMutableProperty<*>.javaSetter: Method?
get() = (this as? KMutablePropertyImpl<*>)?.setter
// TODO: val KTopLevelVariable<*>.javaField: Field
public val KTopLevelVariable<*>.javaGetter: Method
get() = (this as KTopLevelVariableImpl<*>).getter
public val KMutableTopLevelVariable<*>.javaSetter: Method
get() = (this as KMutableTopLevelVariableImpl<*>).setter
public val KTopLevelExtensionProperty<*, *>.javaGetter: Method
get() = (this as KTopLevelExtensionPropertyImpl<*, *>).getter
public val KMutableTopLevelExtensionProperty<*, *>.javaSetter: Method
get() = (this as KMutableTopLevelExtensionPropertyImpl<*, *>).setter
public val KMemberProperty<*, *>.javaField: Field?
get() = (this as KPropertyImpl<*>).field
// Java reflection -> Kotlin reflection
public val <T> Class<T>.kotlin: KClass<T>
get() = kClass(this)
public val Class<*>.kotlinPackage: KPackage
get() = kPackage(this)
public val Field.kotlin: KProperty<*>
get() {
val clazz = getDeclaringClass()
val name = getName()!!
val modifiers = getModifiers()
val static = Modifier.isStatic(modifiers)
val final = Modifier.isFinal(modifiers)
if (static) {
val kPackage = kPackage(clazz)
return if (final) topLevelVariable(name, kPackage) else mutableTopLevelVariable(name, kPackage)
}
else {
val kClass = kClass(clazz as Class<Any>)
return if (final) kClass.memberProperty(name) else kClass.mutableMemberProperty(name)
}
}
@@ -1,54 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.reflect.jvm
import kotlin.reflect.*
import kotlin.reflect.jvm.internal.*
public var <R> KProperty<R>.accessible: Boolean
get() {
return when (this) {
is KMutableMemberPropertyImpl<*, R> ->
field?.isAccessible() ?: true &&
getter?.isAccessible() ?: true &&
setter?.isAccessible() ?: true
is KMemberPropertyImpl<*, R> ->
field?.isAccessible() ?: true &&
getter?.isAccessible() ?: true
is KForeignMemberProperty<*, R> -> field.isAccessible()
else -> {
// Non-member properties always have public visibility on JVM, thus accessible has no effect on them
true
}
}
}
set(value) {
when (this) {
is KMutableMemberPropertyImpl<*, R> -> {
field?.setAccessible(value)
getter?.setAccessible(value)
setter?.setAccessible(value)
}
is KMemberPropertyImpl<*, R> -> {
field?.setAccessible(value)
getter?.setAccessible(value)
}
is KForeignMemberProperty<*, R> -> {
field.setAccessible(value)
}
}
}