Add basic support for class references
Also use class name for `Any.toString` and `Throwable.toString`.
This commit is contained in:
committed by
GitHub
parent
a6ca64871f
commit
786374ef86
+2
-2
@@ -44,8 +44,8 @@ internal class KonanLower(val context: Context) {
|
||||
irModule.files.forEach(TestProcessor(context)::lower)
|
||||
}
|
||||
|
||||
phaser.phase(KonanPhase.LOWER_SPECIAL_CALLS) {
|
||||
irModule.files.forEach(SpecialCallsLowering(context)::lower)
|
||||
phaser.phase(KonanPhase.LOWER_BEFORE_INLINE) {
|
||||
irModule.files.forEach(PreInlineLowering(context)::lower)
|
||||
}
|
||||
|
||||
phaser.phase(KonanPhase.LOWER_INLINE_CONSTRUCTORS) {
|
||||
|
||||
+3
-3
@@ -29,9 +29,9 @@ enum class KonanPhase(val description: String,
|
||||
/* */ BACKEND("All backend"),
|
||||
/* ... */ LOWER("IR Lowering"),
|
||||
/* ... ... */ TEST_PROCESSOR("Unit test processor"),
|
||||
/* ... ... */ LOWER_SPECIAL_CALLS("Special calls processing before inlining"),
|
||||
/* ... ... */ LOWER_INLINE_CONSTRUCTORS("Inline constructors transformation", LOWER_SPECIAL_CALLS),
|
||||
/* ... ... */ LOWER_INLINE("Functions inlining", LOWER_INLINE_CONSTRUCTORS, LOWER_SPECIAL_CALLS),
|
||||
/* ... ... */ LOWER_BEFORE_INLINE("Special operations processing before inlining"),
|
||||
/* ... ... */ LOWER_INLINE_CONSTRUCTORS("Inline constructors transformation", LOWER_BEFORE_INLINE),
|
||||
/* ... ... */ LOWER_INLINE("Functions inlining", LOWER_INLINE_CONSTRUCTORS, LOWER_BEFORE_INLINE),
|
||||
/* ... ... ... */ DESERIALIZER("Deserialize inline bodies"),
|
||||
/* ... ... */ LOWER_INTEROP_PART1("Interop lowering, part 1", LOWER_INLINE),
|
||||
/* ... ... */ LOWER_FOR_LOOPS("For loops lowering"),
|
||||
|
||||
+23
-1
@@ -28,10 +28,15 @@ import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import kotlin.properties.Delegates
|
||||
@@ -89,6 +94,12 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
|
||||
it to symbolTable.referenceClass(context.getInternalClass("${it.classFqName.shortName()}Box"))
|
||||
}
|
||||
|
||||
val valueClassToBox = ValueType.values().associate {
|
||||
val valueClassId = ClassId.topLevel(it.classFqName.toSafe())
|
||||
val valueClassDescriptor = context.builtIns.builtInsModule.findClassAcrossModuleDependencies(valueClassId)!!
|
||||
valueClassDescriptor to boxClasses[it]!!
|
||||
}
|
||||
|
||||
val unboxFunctions = ValueType.values().mapNotNull {
|
||||
val unboxFunctionName = "unbox${it.classFqName.shortName()}"
|
||||
context.getInternalFunctions(unboxFunctionName).atMostOne()?.let { descriptor ->
|
||||
@@ -170,6 +181,17 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
|
||||
val kLocalDelegatedPropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedPropertyImpl)
|
||||
val kLocalDelegatedMutablePropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedMutablePropertyImpl)
|
||||
|
||||
val getClassTypeInfo = internalFunction("getClassTypeInfo")
|
||||
val getObjectTypeInfo = internalFunction("getObjectTypeInfo")
|
||||
val kClassImpl = internalClass("KClassImpl")
|
||||
val kClassImplConstructor by lazy { kClassImpl.constructors.single() }
|
||||
|
||||
private fun internalFunction(name: String): IrSimpleFunctionSymbol =
|
||||
symbolTable.referenceSimpleFunction(context.getInternalFunctions(name).single())
|
||||
|
||||
private fun internalClass(name: String): IrClassSymbol =
|
||||
symbolTable.referenceClass(context.getInternalClass(name))
|
||||
|
||||
private fun getKonanTestClass(className: String) = symbolTable.referenceClass(
|
||||
builtInsPackage("konan", "test").getContributedClassifier(
|
||||
Name.identifier(className), NoLookupLocation.FROM_BACKEND
|
||||
@@ -216,4 +238,4 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
|
||||
kind.runtimeKindName, NoLookupLocation.FROM_BACKEND
|
||||
) as ClassDescriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-2
@@ -1386,8 +1386,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
private fun evaluateStringConst(value: IrConst<String>) =
|
||||
context.llvm.staticData.kotlinStringLiteral(
|
||||
context.builtIns.stringType, value).llvm
|
||||
context.llvm.staticData.kotlinStringLiteral(value.value).llvm
|
||||
|
||||
private fun evaluateConst(value: IrConst<*>): LLVMValueRef {
|
||||
context.log{"evaluateConst : ${ir2string(value)}"}
|
||||
@@ -2007,6 +2006,22 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
interop.readBits -> genReadBits(args)
|
||||
interop.writeBits -> genWriteBits(args)
|
||||
|
||||
context.ir.symbols.getClassTypeInfo.descriptor -> {
|
||||
val typeArgument = callee.getTypeArgumentOrDefault(descriptor.typeParameters.single())
|
||||
val typeArgumentClass = TypeUtils.getClassDescriptor(typeArgument)
|
||||
if (typeArgumentClass == null) {
|
||||
// E.g. for `T::class` in a body of an inline function itself.
|
||||
functionGenerationContext.unreachable()
|
||||
kNullInt8Ptr
|
||||
} else {
|
||||
val classDescriptor = context.ir.symbols.valueClassToBox[typeArgumentClass]?.descriptor
|
||||
?: typeArgumentClass
|
||||
|
||||
val typeInfo = codegen.typeInfoValue(classDescriptor)
|
||||
LLVMConstBitCast(typeInfo, kInt8Ptr)!!
|
||||
}
|
||||
}
|
||||
|
||||
else -> TODO(callee.descriptor.original.toString())
|
||||
}
|
||||
}
|
||||
|
||||
+43
-3
@@ -23,9 +23,11 @@ import org.jetbrains.kotlin.backend.konan.isExternalObjCClassMethod
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
|
||||
|
||||
|
||||
internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
@@ -45,7 +47,9 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
val methods: ConstValue,
|
||||
val methodsCount: Int,
|
||||
val fields: ConstValue,
|
||||
val fieldsCount: Int) :
|
||||
val fieldsCount: Int,
|
||||
val packageName: String?,
|
||||
val relativeName: String?) :
|
||||
Struct(
|
||||
runtime.typeInfoType,
|
||||
|
||||
@@ -64,9 +68,18 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
Int32(methodsCount),
|
||||
|
||||
fields,
|
||||
Int32(fieldsCount)
|
||||
Int32(fieldsCount),
|
||||
|
||||
kotlinStringLiteral(packageName),
|
||||
kotlinStringLiteral(relativeName)
|
||||
)
|
||||
|
||||
private fun kotlinStringLiteral(string: String?): ConstPointer = if (string == null) {
|
||||
NullPointer(runtime.objHeaderType)
|
||||
} else {
|
||||
staticData.kotlinStringLiteral(string)
|
||||
}
|
||||
|
||||
private fun exportTypeInfoIfRequired(classDesc: ClassDescriptor, typeInfoGlobal: LLVMValueRef?) {
|
||||
val annot = classDesc.annotations.findAnnotation(FqName("konan.ExportTypeInfo"))
|
||||
if (annot != null) {
|
||||
@@ -159,12 +172,17 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
val methodsPtr = staticData.placeGlobalConstArray("kmethods:$className",
|
||||
runtime.methodTableRecordType, methods)
|
||||
|
||||
val reflectionInfo = getReflectionInfo(classDesc)
|
||||
|
||||
val typeInfo = TypeInfo(name, size,
|
||||
superType,
|
||||
objOffsetsPtr, objOffsets.size,
|
||||
interfacesPtr, interfaces.size,
|
||||
methodsPtr, methods.size,
|
||||
fieldsPtr, if (classDesc.isInterface) -1 else fields.size)
|
||||
fieldsPtr, if (classDesc.isInterface) -1 else fields.size,
|
||||
reflectionInfo.packageName,
|
||||
reflectionInfo.relativeName
|
||||
)
|
||||
|
||||
val typeInfoGlobal = llvmDeclarations.typeInfoGlobal
|
||||
|
||||
@@ -201,4 +219,26 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
}
|
||||
return context.specialDeclarationsFactory.getBridgeDescriptor(OverriddenFunctionDescriptor(bridgeOwner, overriddenDescriptor))
|
||||
}
|
||||
|
||||
data class ReflectionInfo(val packageName: String?, val relativeName: String?)
|
||||
|
||||
private fun getReflectionInfo(descriptor: ClassDescriptor): ReflectionInfo {
|
||||
// Use data from value class in type info for box class:
|
||||
val descriptorForReflection = context.ir.symbols.valueClassToBox.entries
|
||||
.firstOrNull { it.value.descriptor == descriptor }
|
||||
?.key ?: descriptor
|
||||
|
||||
return if (DescriptorUtils.isAnonymousObject(descriptorForReflection)) {
|
||||
ReflectionInfo(packageName = null, relativeName = null)
|
||||
} else if (DescriptorUtils.isLocal(descriptorForReflection)) {
|
||||
ReflectionInfo(packageName = null, relativeName = descriptorForReflection.name.asString())
|
||||
} else {
|
||||
ReflectionInfo(
|
||||
packageName = descriptorForReflection.findPackage().fqName.asString(),
|
||||
relativeName = descriptorForReflection.parentsWithSelf
|
||||
.takeWhile { it is ClassDescriptor }.toList().reversed()
|
||||
.joinToString(".") { it.name.asString() }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -157,8 +157,8 @@ internal class StaticData(override val context: Context): ContextUtils {
|
||||
fun cStringLiteral(value: String) =
|
||||
cStringLiterals.getOrPut(value) { placeCStringLiteral(value) }
|
||||
|
||||
fun kotlinStringLiteral(type: KotlinType, value: IrConst<String>) =
|
||||
stringLiterals.getOrPut(value.value) { createKotlinStringLiteral(type, value) }
|
||||
fun kotlinStringLiteral(value: String) =
|
||||
stringLiterals.getOrPut(value) { createKotlinStringLiteral(value) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-2
@@ -42,8 +42,9 @@ private fun StaticData.arrayHeader(typeInfo: ConstPointer, length: Int): Struct
|
||||
return Struct(runtime.arrayHeaderType, typeInfo, Int32(containerOffsetNegative), Int32(length))
|
||||
}
|
||||
|
||||
internal fun StaticData.createKotlinStringLiteral(type: KotlinType, irConst: IrConst<String>): ConstPointer {
|
||||
val value = irConst.value
|
||||
internal fun StaticData.createKotlinStringLiteral(value: String): ConstPointer {
|
||||
val type = context.builtIns.stringType
|
||||
|
||||
val name = "kstr:" + value.globalHashBase64
|
||||
val elements = value.toCharArray().map(::Char16)
|
||||
|
||||
|
||||
+36
-11
@@ -1,33 +1,58 @@
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.IrBuildingTransformer
|
||||
import org.jetbrains.kotlin.backend.common.lower.at
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrSpreadElement
|
||||
import org.jetbrains.kotlin.ir.expressions.IrVararg
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
|
||||
/**
|
||||
* This pass runs before inlining and performs the following additional transformations over some calls:
|
||||
* This pass runs before inlining and performs the following additional transformations over some operations:
|
||||
* - Assertion call removal.
|
||||
* - Convert immutableBinaryBlobOf() arguments to special IrConst.
|
||||
* - Convert `obj::class` and `Class::class` to calls.
|
||||
*/
|
||||
internal class SpecialCallsLowering(val context: Context) : FileLoweringPass {
|
||||
internal class PreInlineLowering(val context: Context) : FileLoweringPass {
|
||||
|
||||
private val asserts = context.ir.symbols.asserts
|
||||
private val symbols get() = context.ir.symbols
|
||||
|
||||
private val asserts = symbols.asserts
|
||||
private val enableAssertions = context.config.configuration.getBoolean(KonanConfigKeys.ENABLE_ASSERTIONS)
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
irFile.transformChildrenVoid(object : IrBuildingTransformer(context) {
|
||||
|
||||
override fun visitClassReference(expression: IrClassReference): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
builder.at(expression)
|
||||
|
||||
val typeArgument = expression.descriptor.defaultType
|
||||
|
||||
return builder.irCall(symbols.kClassImplConstructor, listOf(typeArgument)).apply {
|
||||
putValueArgument(0, builder.irCall(symbols.getClassTypeInfo, listOf(typeArgument)))
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitGetClass(expression: IrGetClass): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
builder.at(expression)
|
||||
|
||||
val typeArgument = expression.type.arguments.single().type
|
||||
return builder.irCall(symbols.kClassImplConstructor, listOf(typeArgument)).apply {
|
||||
val typeInfo = builder.irCall(symbols.getObjectTypeInfo).apply {
|
||||
putValueArgument(0, expression.argument)
|
||||
}
|
||||
|
||||
putValueArgument(0, typeInfo)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
@@ -928,6 +928,15 @@ task lateinit_inBaseClass(type: RunKonanTest) {
|
||||
source = "codegen/lateinit/inBaseClass.kt"
|
||||
}
|
||||
|
||||
task kclass0(type: RunKonanTest) {
|
||||
source = "codegen/kclass/kclass0.kt"
|
||||
}
|
||||
|
||||
task kclass1(type: RunKonanTest) {
|
||||
goldValue = "OK :D\n"
|
||||
source = "codegen/kclass/kclass1.kt"
|
||||
}
|
||||
|
||||
task coroutines_simple(type: RunKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // llvm: 'WebAssembly hasn't implemented computed gotos'
|
||||
goldValue = "42\n"
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
checkClass(Any::class, "kotlin.Any", "Any", Any(), null)
|
||||
checkClass(Int::class, "kotlin.Int", "Int", 42, "17")
|
||||
checkClass(String::class, "kotlin.String", "String", "17", 42)
|
||||
checkClass(RootClass::class, "RootClass", "RootClass", RootClass(), Any())
|
||||
checkClass(RootClass.Nested::class, "RootClass.Nested", "Nested", RootClass.Nested(), Any())
|
||||
|
||||
class Local {
|
||||
val captured = args
|
||||
|
||||
inner class Inner
|
||||
}
|
||||
checkClass(Local::class, null, "Local", Local(), Any())
|
||||
checkClass(Local.Inner::class, null, "Inner", Local().Inner(), Any())
|
||||
|
||||
val obj = object : Any() {
|
||||
val captured = args
|
||||
|
||||
inner class Inner
|
||||
val innerKClass = Inner::class
|
||||
}
|
||||
checkClass(obj::class, null, null, obj, Any())
|
||||
checkClass(obj.innerKClass, null, "Inner", obj.Inner(), Any())
|
||||
|
||||
// Interfaces:
|
||||
checkClass(Comparable::class, "kotlin.Comparable", "Comparable", 42, Any())
|
||||
checkClass(Interface::class, "Interface", "Interface", object : Interface {}, Any())
|
||||
|
||||
checkInstanceClass(Any(), Any::class)
|
||||
checkInstanceClass(42, Int::class)
|
||||
assert(42::class == Int::class)
|
||||
|
||||
checkReifiedClass<Int>(Int::class)
|
||||
checkReifiedClass<Int?>(Int::class)
|
||||
checkReifiedClass2<Int>(Int::class)
|
||||
checkReifiedClass2<Int?>(Int::class)
|
||||
checkReifiedClass<Any>(Any::class)
|
||||
checkReifiedClass2<Any>(Any::class)
|
||||
checkReifiedClass2<Any?>(Any::class)
|
||||
checkReifiedClass<Local>(Local::class)
|
||||
checkReifiedClass2<Local>(Local::class)
|
||||
checkReifiedClass<RootClass>(RootClass::class)
|
||||
checkReifiedClass2<RootClass>(RootClass::class)
|
||||
}
|
||||
|
||||
class RootClass {
|
||||
class Nested
|
||||
}
|
||||
interface Interface
|
||||
|
||||
fun checkClass(
|
||||
clazz: KClass<*>,
|
||||
expectedQualifiedName: String?, expectedSimpleName: String?,
|
||||
expectedInstance: Any, expectedNotInstance: Any?
|
||||
) {
|
||||
assert(clazz.qualifiedName == expectedQualifiedName)
|
||||
assert(clazz.simpleName == expectedSimpleName)
|
||||
|
||||
assert(clazz.isInstance(expectedInstance))
|
||||
if (expectedNotInstance != null) assert(!clazz.isInstance(expectedNotInstance))
|
||||
}
|
||||
|
||||
fun checkInstanceClass(instance: Any, clazz: KClass<*>) {
|
||||
assert(instance::class == clazz)
|
||||
}
|
||||
|
||||
inline fun <reified T> checkReifiedClass(expectedClass: KClass<*>) {
|
||||
assert(T::class == expectedClass)
|
||||
}
|
||||
|
||||
inline fun <reified T> checkReifiedClass2(expectedClass: KClass<*>) {
|
||||
checkReifiedClass<T>(expectedClass)
|
||||
checkReifiedClass<T?>(expectedClass)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// FILE: main.kt
|
||||
fun main(args: Array<String>) {
|
||||
com.github.salomonbrys.kmffkn.App(testQualified = true)
|
||||
}
|
||||
|
||||
// FILE: app.kt
|
||||
|
||||
// Taken from:
|
||||
// https://github.com/SalomonBrys/kmffkn/blob/master/shared/main/kotlin/com/github/salomonbrys/kmffkn/app.kt
|
||||
|
||||
package com.github.salomonbrys.kmffkn
|
||||
|
||||
@DslMarker
|
||||
annotation class MyDsl
|
||||
|
||||
@MyDsl
|
||||
class DslMain {
|
||||
fun <T: Any> kClass(block: KClassDsl.() -> T): T = KClassDsl().block()
|
||||
}
|
||||
|
||||
@MyDsl
|
||||
class KClassDsl {
|
||||
inline fun <reified T: Any> of() = T::class
|
||||
}
|
||||
|
||||
fun <T: Any> dsl(block: DslMain.() -> T): T = DslMain().block()
|
||||
|
||||
class Test
|
||||
|
||||
class App(testQualified: Boolean) {
|
||||
|
||||
@Volatile // This could be noop in Kotlin Native, or the equivalent of volatile in C.
|
||||
var type = dsl {
|
||||
kClass {
|
||||
//kClass { } // This should error if uncommented because of `@DslMarker`.
|
||||
of<Test>()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
assert(type.simpleName == "Test")
|
||||
if (testQualified)
|
||||
assert(type.qualifiedName == "com.github.salomonbrys.kmffkn.Test") // This is not really necessary, but always better :).
|
||||
|
||||
assert(String::class == String::class)
|
||||
assert(String::class != Int::class)
|
||||
|
||||
assert(Test()::class == Test()::class)
|
||||
assert(Test()::class == Test::class)
|
||||
|
||||
println("OK :D")
|
||||
}
|
||||
}
|
||||
@@ -70,4 +70,8 @@ void Kotlin_system_exitProcess(KInt status) {
|
||||
konan::exit(status);
|
||||
}
|
||||
|
||||
const void* Kotlin_Any_getTypeInfo(KConstRef obj) {
|
||||
return obj->type_info();
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -68,18 +68,6 @@ template <typename T> OBJ_GETTER(Kotlin_toStringRadix, T value, KInt radix) {
|
||||
|
||||
extern "C" {
|
||||
|
||||
OBJ_GETTER(Kotlin_Any_toString, KConstRef thiz) {
|
||||
char cstring[80];
|
||||
if (IsArray(thiz)) {
|
||||
konan::snprintf(cstring, sizeof(cstring), "%d@%p: array of %d",
|
||||
Kotlin_Any_hashCode(thiz), thiz->type_info_, thiz->array()->count_);
|
||||
} else {
|
||||
konan::snprintf(cstring, sizeof(cstring), "%d@%p: object",
|
||||
Kotlin_Any_hashCode(thiz), thiz->type_info_);
|
||||
}
|
||||
RETURN_RESULT_OF(CreateStringFromCString, cstring);
|
||||
}
|
||||
|
||||
OBJ_GETTER(Kotlin_Byte_toString, KByte value) {
|
||||
char cstring[8];
|
||||
konan::snprintf(cstring, sizeof(cstring), "%d", value);
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "Common.h"
|
||||
#include "Names.h"
|
||||
|
||||
struct ObjHeader;
|
||||
|
||||
// An element of sorted by hash in-place array representing methods.
|
||||
// For systems where introspection is not needed - only open methods are in
|
||||
// this table.
|
||||
@@ -56,6 +58,15 @@ struct TypeInfo {
|
||||
// Is negative to mark an interface.
|
||||
int32_t fieldsCount_;
|
||||
|
||||
// String for the fully qualified dot-separated name of the package containing class,
|
||||
// or `null` if the class is local or anonymous.
|
||||
ObjHeader* packageName_;
|
||||
|
||||
// String for the qualified class name relative to the containing package
|
||||
// (e.g. TopLevel.Nested1.Nested2), or simple class name if it is local,
|
||||
// or `null` if the class is anonymous.
|
||||
ObjHeader* relativeName_;
|
||||
|
||||
// vtable starts just after declared contents of the TypeInfo:
|
||||
// void* const vtable_[];
|
||||
};
|
||||
|
||||
@@ -50,4 +50,16 @@ void CheckInstance(const ObjHeader* obj, const TypeInfo* type_info) {
|
||||
ThrowClassCastException();
|
||||
}
|
||||
|
||||
KBoolean Kotlin_TypeInfo_isInstance(KConstRef obj, KNativePtr typeInfo) {
|
||||
return IsInstance(obj, reinterpret_cast<const TypeInfo*>(typeInfo));
|
||||
}
|
||||
|
||||
OBJ_GETTER(Kotlin_TypeInfo_getPackageName, KNativePtr typeInfo) {
|
||||
RETURN_OBJ(reinterpret_cast<const TypeInfo*>(typeInfo)->packageName_);
|
||||
}
|
||||
|
||||
OBJ_GETTER(Kotlin_TypeInfo_getRelativeName, KNativePtr typeInfo) {
|
||||
RETURN_OBJ(reinterpret_cast<const TypeInfo*>(typeInfo)->relativeName_);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 konan.internal
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@ExportForCompiler
|
||||
internal class KClassImpl<T : Any>(private val typeInfo: NativePtr) : KClass<T> {
|
||||
override val simpleName: String?
|
||||
get() {
|
||||
val relativeName = getRelativeName(typeInfo)
|
||||
?: return null
|
||||
|
||||
return relativeName.substringAfterLast(".")
|
||||
}
|
||||
|
||||
override val qualifiedName: String?
|
||||
get() {
|
||||
val packageName = getPackageName(typeInfo)
|
||||
?: return null
|
||||
|
||||
val relativeName = getRelativeName(typeInfo)!!
|
||||
return if (packageName.isEmpty()) {
|
||||
relativeName
|
||||
} else {
|
||||
"$packageName.$relativeName"
|
||||
}
|
||||
}
|
||||
|
||||
override fun isInstance(value: Any?): Boolean = value != null && isInstance(value, this.typeInfo)
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is KClassImpl<*> && this.typeInfo == other.typeInfo
|
||||
|
||||
override fun hashCode(): Int = typeInfo.hashCode()
|
||||
}
|
||||
|
||||
@ExportForCompiler
|
||||
@SymbolName("Kotlin_Any_getTypeInfo")
|
||||
internal external fun getObjectTypeInfo(obj: Any): NativePtr
|
||||
|
||||
@ExportForCompiler
|
||||
@Intrinsic
|
||||
internal external inline fun <reified T : Any> getClassTypeInfo(): NativePtr
|
||||
|
||||
@SymbolName("Kotlin_TypeInfo_getPackageName")
|
||||
private external fun getPackageName(typeInfo: NativePtr): String?
|
||||
|
||||
@SymbolName("Kotlin_TypeInfo_getRelativeName")
|
||||
private external fun getRelativeName(typeInfo: NativePtr): String?
|
||||
|
||||
@SymbolName("Kotlin_TypeInfo_isInstance")
|
||||
private external fun isInstance(obj: Any, typeInfo: NativePtr): Boolean
|
||||
@@ -48,8 +48,13 @@ public open class Any {
|
||||
/**
|
||||
* Returns a string representation of the object.
|
||||
*/
|
||||
@SymbolName("Kotlin_Any_toString")
|
||||
external public open fun toString(): String
|
||||
public open fun toString(): String {
|
||||
val kClass = this::class
|
||||
val className = kClass.qualifiedName ?: kClass.simpleName ?: "<object>"
|
||||
val unsignedHashCode = this.hashCode().toLong() and 0xffffffffL
|
||||
val hashCodeStr = unsignedHashCode.toString(16)
|
||||
return "$className@$hashCodeStr"
|
||||
}
|
||||
}
|
||||
|
||||
public fun Any?.hashCode() = if (this != null) this.hashCode() else 0
|
||||
@@ -50,7 +50,8 @@ public open class Throwable(open val message: String?, open val cause: Throwable
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val s = "Throwable" // TODO: should be class name
|
||||
val kClass = this::class
|
||||
val s = kClass.qualifiedName ?: kClass.simpleName ?: "Throwable"
|
||||
return if (message != null) s + ": " + message.toString() else s
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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 kotlin.reflect
|
||||
|
||||
/**
|
||||
* Represents a class and provides introspection capabilities.
|
||||
* Instances of this class are obtainable by the `::class` syntax.
|
||||
* See the [Kotlin language documentation](http://kotlinlang.org/docs/reference/reflection.html#class-references)
|
||||
* for more information.
|
||||
*
|
||||
* @param T the type of the class.
|
||||
*/
|
||||
public interface KClass<T : Any> : KDeclarationContainer, KAnnotatedElement, KClassifier {
|
||||
/**
|
||||
* The simple name of the class as it was declared in the source code,
|
||||
* or `null` if the class has no name (if, for example, it is an anonymous object literal).
|
||||
*/
|
||||
public val simpleName: String?
|
||||
|
||||
/**
|
||||
* The fully qualified dot-separated name of the class,
|
||||
* or `null` if the class is local or it is an anonymous object literal.
|
||||
*/
|
||||
public val qualifiedName: String?
|
||||
|
||||
// /**
|
||||
// * All functions and properties accessible in this class, including those declared in this class
|
||||
// * and all of its superclasses. Does not include constructors.
|
||||
// */
|
||||
// override val members: Collection<KCallable<*>>
|
||||
//
|
||||
// /**
|
||||
// * All constructors declared in this class.
|
||||
// */
|
||||
// public val constructors: Collection<KFunction<T>>
|
||||
//
|
||||
// /**
|
||||
// * All classes declared inside this class. This includes both inner and static nested classes.
|
||||
// */
|
||||
// public val nestedClasses: Collection<KClass<*>>
|
||||
//
|
||||
// /**
|
||||
// * The instance of the object declaration, or `null` if this class is not an object declaration.
|
||||
// */
|
||||
// public val objectInstance: T?
|
||||
|
||||
/**
|
||||
* Returns `true` if [value] is an instance of this class on a given platform.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public fun isInstance(value: Any?): Boolean
|
||||
|
||||
// /**
|
||||
// * The list of type parameters of this class. This list does *not* include type parameters of outer classes.
|
||||
// */
|
||||
// @SinceKotlin("1.1")
|
||||
// public val typeParameters: List<KTypeParameter>
|
||||
//
|
||||
// /**
|
||||
// * The list of immediate supertypes of this class, in the order they are listed in the source code.
|
||||
// */
|
||||
// @SinceKotlin("1.1")
|
||||
// public val supertypes: List<KType>
|
||||
//
|
||||
// /**
|
||||
// * Visibility of this class, or `null` if its visibility cannot be represented in Kotlin.
|
||||
// */
|
||||
// @SinceKotlin("1.1")
|
||||
// public val visibility: KVisibility?
|
||||
//
|
||||
// /**
|
||||
// * `true` if this class is `final`.
|
||||
// */
|
||||
// @SinceKotlin("1.1")
|
||||
// public val isFinal: Boolean
|
||||
//
|
||||
// /**
|
||||
// * `true` if this class is `open`.
|
||||
// */
|
||||
// @SinceKotlin("1.1")
|
||||
// public val isOpen: Boolean
|
||||
//
|
||||
// /**
|
||||
// * `true` if this class is `abstract`.
|
||||
// */
|
||||
// @SinceKotlin("1.1")
|
||||
// public val isAbstract: Boolean
|
||||
//
|
||||
// /**
|
||||
// * `true` if this class is `sealed`.
|
||||
// * See the [Kotlin language documentation](https://kotlinlang.org/docs/reference/classes.html#sealed-classes)
|
||||
// * for more information.
|
||||
// */
|
||||
// @SinceKotlin("1.1")
|
||||
// public val isSealed: Boolean
|
||||
//
|
||||
// /**
|
||||
// * `true` if this class is a data class.
|
||||
// * See the [Kotlin language documentation](https://kotlinlang.org/docs/reference/data-classes.html)
|
||||
// * for more information.
|
||||
// */
|
||||
// @SinceKotlin("1.1")
|
||||
// public val isData: Boolean
|
||||
//
|
||||
// /**
|
||||
// * `true` if this class is an inner class.
|
||||
// * See the [Kotlin language documentation](https://kotlinlang.org/docs/reference/nested-classes.html#inner-classes)
|
||||
// * for more information.
|
||||
// */
|
||||
// @SinceKotlin("1.1")
|
||||
// public val isInner: Boolean
|
||||
//
|
||||
// /**
|
||||
// * `true` if this class is a companion object.
|
||||
// * See the [Kotlin language documentation](https://kotlinlang.org/docs/reference/object-declarations.html#companion-objects)
|
||||
// * for more information.
|
||||
// */
|
||||
// @SinceKotlin("1.1")
|
||||
// public val isCompanion: Boolean
|
||||
|
||||
/**
|
||||
* Returns `true` if this [KClass] instance represents the same Kotlin class as the class represented by [other].
|
||||
* On JVM this means that all of the following conditions are satisfied:
|
||||
*
|
||||
* 1. [other] has the same (fully qualified) Kotlin class name as this instance.
|
||||
* 2. [other]'s backing [Class] object is loaded with the same class loader as the [Class] object of this instance.
|
||||
* 3. If the classes represent [Array], then [Class] objects of their element types are equal.
|
||||
*
|
||||
* For example, on JVM, [KClass] instances for a primitive type (`int`) and the corresponding wrapper type (`java.lang.Integer`)
|
||||
* are considered equal, because they have the same fully qualified name "kotlin.Int".
|
||||
*/
|
||||
override fun equals(other: Any?): Boolean
|
||||
|
||||
override fun hashCode(): Int
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 kotlin.reflect
|
||||
|
||||
/**
|
||||
* A classifier is either a class or a type parameter.
|
||||
*
|
||||
* @see [KClass]
|
||||
* @see [KTypeParameter]
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public interface KClassifier
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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 kotlin.reflect
|
||||
|
||||
/**
|
||||
* Represents an entity which may contain declarations of any other entities,
|
||||
* such as a class or a package.
|
||||
*/
|
||||
public interface KDeclarationContainer {
|
||||
// /**
|
||||
// * All functions and properties accessible in this container.
|
||||
// */
|
||||
// public val members: Collection<KCallable<*>>
|
||||
}
|
||||
Reference in New Issue
Block a user