Fix enum entries processing in C reverse interop. (#1232)
This commit is contained in:
+48
-3
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.konan
|
package org.jetbrains.kotlin.backend.konan
|
||||||
|
|
||||||
|
import kotlinx.cinterop.cValuesOf
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import llvm.*
|
import llvm.*
|
||||||
import org.jetbrains.kotlin.backend.common.descriptors.allParameters
|
import org.jetbrains.kotlin.backend.common.descriptors.allParameters
|
||||||
@@ -34,6 +35,7 @@ import org.jetbrains.kotlin.name.isChildOf
|
|||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
private enum class ScopeKind {
|
private enum class ScopeKind {
|
||||||
TOP,
|
TOP,
|
||||||
@@ -183,7 +185,6 @@ private class ExportedElement(val kind: ElementKind,
|
|||||||
val result = call(callee, args, exceptionHandler = ExceptionHandler.Caller, verbatim = true)
|
val result = call(callee, args, exceptionHandler = ExceptionHandler.Caller, verbatim = true)
|
||||||
ret(result)
|
ret(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LLVMAddAlias(context.llvmModule, llvmFunction.type, llvmFunction, cname)!!
|
LLVMAddAlias(context.llvmModule, llvmFunction.type, llvmFunction, cname)!!
|
||||||
}
|
}
|
||||||
@@ -199,13 +200,23 @@ private class ExportedElement(val kind: ElementKind,
|
|||||||
LLVMBuildRet(builder, (declaration as ClassDescriptor).typeInfoPtr.llvm)
|
LLVMBuildRet(builder, (declaration as ClassDescriptor).typeInfoPtr.llvm)
|
||||||
LLVMDisposeBuilder(builder)
|
LLVMDisposeBuilder(builder)
|
||||||
}
|
}
|
||||||
|
isEnumEntry -> {
|
||||||
|
// Produce entry getter.
|
||||||
|
cname = "_konan_function_${owner.nextFunctionIndex()}"
|
||||||
|
generateFunction(owner.codegen, owner.kGetObjectFuncType, cname) {
|
||||||
|
val value = getEnumEntry(declaration as ClassDescriptor, ExceptionHandler.Caller)
|
||||||
|
ret(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun uniqueName(descriptor: DeclarationDescriptor) = scope.scopeUniqueName(descriptor)
|
fun uniqueName(descriptor: DeclarationDescriptor) = scope.scopeUniqueName(descriptor)
|
||||||
|
|
||||||
val isFunction = declaration is FunctionDescriptor
|
val isFunction = declaration is FunctionDescriptor
|
||||||
val isClass = declaration is ClassDescriptor
|
val isClass = declaration is ClassDescriptor && declaration.kind != ClassKind.ENUM_ENTRY
|
||||||
|
val isEnumClass = declaration is ClassDescriptor && declaration.kind == ClassKind.ENUM_CLASS
|
||||||
|
val isEnumEntry = declaration is ClassDescriptor && declaration.kind == ClassKind.ENUM_ENTRY
|
||||||
|
|
||||||
fun makeCFunctionSignature(): List<Pair<String, ClassDescriptor>> {
|
fun makeCFunctionSignature(): List<Pair<String, ClassDescriptor>> {
|
||||||
if (!isFunction) {
|
if (!isFunction) {
|
||||||
@@ -215,7 +226,7 @@ private class ExportedElement(val kind: ElementKind,
|
|||||||
val original = descriptor.original as FunctionDescriptor
|
val original = descriptor.original as FunctionDescriptor
|
||||||
val returned = when {
|
val returned = when {
|
||||||
original is ConstructorDescriptor -> uniqueName(original) to original.constructedClass
|
original is ConstructorDescriptor -> uniqueName(original) to original.constructedClass
|
||||||
// Suspend functions actually return Any?.
|
// Suspend functions actually return 'Any?'.
|
||||||
original.isSuspend -> uniqueName(original) to
|
original.isSuspend -> uniqueName(original) to
|
||||||
TypeUtils.getClassDescriptor(owner.context.builtIns.nullableAnyType)!!
|
TypeUtils.getClassDescriptor(owner.context.builtIns.nullableAnyType)!!
|
||||||
else -> uniqueName(original) to TypeUtils.getClassDescriptor(original.returnType!!)!!
|
else -> uniqueName(original) to TypeUtils.getClassDescriptor(original.returnType!!)!!
|
||||||
@@ -271,6 +282,21 @@ private class ExportedElement(val kind: ElementKind,
|
|||||||
return "extern \"C\" ${owner.prefix}_KType* $cname(void);"
|
return "extern \"C\" ${owner.prefix}_KType* $cname(void);"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun makeEnumEntryDeclaration(): String {
|
||||||
|
assert(isEnumEntry)
|
||||||
|
val enumClass = declaration.containingDeclaration as ClassDescriptor
|
||||||
|
val enumClassC = owner.translateType(enumClass)
|
||||||
|
|
||||||
|
return """
|
||||||
|
|extern "C" KObjHeader* $cname(KObjHeader**);
|
||||||
|
|static $enumClassC ${cname}_impl(void) {
|
||||||
|
| KObjHolder result_holder;
|
||||||
|
| KObjHeader* result = $cname(result_holder.slot());
|
||||||
|
| return $enumClassC { .pinned = CreateStablePointer(result)};
|
||||||
|
|}
|
||||||
|
""".trimMargin()
|
||||||
|
}
|
||||||
|
|
||||||
private fun translateArgument(name: String, clazz: ClassDescriptor, direction: Direction,
|
private fun translateArgument(name: String, clazz: ClassDescriptor, direction: Direction,
|
||||||
builder: StringBuilder): String {
|
builder: StringBuilder): String {
|
||||||
val fqName = clazz.fqNameSafe.asString()
|
val fqName = clazz.fqNameSafe.asString()
|
||||||
@@ -509,6 +535,14 @@ internal class CAdapterGenerator(
|
|||||||
fun generateBindings() {
|
fun generateBindings() {
|
||||||
scopes.push(ExportedElementScope(ScopeKind.TOP, "kotlin"))
|
scopes.push(ExportedElementScope(ScopeKind.TOP, "kotlin"))
|
||||||
context.moduleDescriptor.accept(this, null)
|
context.moduleDescriptor.accept(this, null)
|
||||||
|
// TODO: add few predefined types.
|
||||||
|
listOf<KotlinType>(
|
||||||
|
// context.builtIns.anyType,
|
||||||
|
// context.builtIns.getPrimitiveArrayKotlinType(PrimitiveType.INT)
|
||||||
|
).forEach {
|
||||||
|
TypeUtils.getClassDescriptor(it)!!.accept(this@CAdapterGenerator, null)
|
||||||
|
}
|
||||||
|
|
||||||
val top = scopes.pop()
|
val top = scopes.pop()
|
||||||
assert(scopes.isEmpty() && top.kind == ScopeKind.TOP)
|
assert(scopes.isEmpty() && top.kind == ScopeKind.TOP)
|
||||||
|
|
||||||
@@ -532,6 +566,10 @@ internal class CAdapterGenerator(
|
|||||||
output(element.makeFunctionPointerString(), indent)
|
output(element.makeFunctionPointerString(), indent)
|
||||||
element.isClass ->
|
element.isClass ->
|
||||||
output("${prefix}_KType* (*_type)(void);", indent)
|
output("${prefix}_KType* (*_type)(void);", indent)
|
||||||
|
element.isEnumEntry -> {
|
||||||
|
val enumClass = element.declaration.containingDeclaration as ClassDescriptor
|
||||||
|
output("${translateType(enumClass)} (*get)(); /* enum entry for ${element.name}. */", indent)
|
||||||
|
}
|
||||||
// TODO: handle properties.
|
// TODO: handle properties.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -542,6 +580,8 @@ internal class CAdapterGenerator(
|
|||||||
output(element.makeFunctionDeclaration(), 0)
|
output(element.makeFunctionDeclaration(), 0)
|
||||||
element.isClass ->
|
element.isClass ->
|
||||||
output(element.makeClassDeclaration(), 0)
|
output(element.makeClassDeclaration(), 0)
|
||||||
|
element.isEnumEntry ->
|
||||||
|
output(element.makeEnumEntryDeclaration(), 0)
|
||||||
// TODO: handle properties.
|
// TODO: handle properties.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -552,6 +592,8 @@ internal class CAdapterGenerator(
|
|||||||
output("/* ${element.name} = */ ${element.cname}_impl, ", indent)
|
output("/* ${element.name} = */ ${element.cname}_impl, ", indent)
|
||||||
element.isClass ->
|
element.isClass ->
|
||||||
output("/* Type for ${element.name} = */ ${element.cname}, ", indent)
|
output("/* Type for ${element.name} = */ ${element.cname}, ", indent)
|
||||||
|
element.isEnumEntry ->
|
||||||
|
output("/* enum entry getter ${element.name} = */ ${element.cname}_impl", indent)
|
||||||
// TODO: handle properties.
|
// TODO: handle properties.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -775,4 +817,7 @@ internal class CAdapterGenerator(
|
|||||||
|
|
||||||
internal val kGetTypeFuncType =
|
internal val kGetTypeFuncType =
|
||||||
LLVMFunctionType(codegen.kTypeInfoPtr, null, 0, 0)!!
|
LLVMFunctionType(codegen.kTypeInfoPtr, null, 0, 0)!!
|
||||||
|
// Abstraction leak for slot :(.
|
||||||
|
internal val kGetObjectFuncType =
|
||||||
|
LLVMFunctionType(codegen.kObjHeaderPtr, cValuesOf(codegen.kObjHeaderPtrPtr), 1, 0)!!
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2361,7 +2361,9 @@ task produce_dynamic(type: DynamicKonanTest) {
|
|||||||
"Impl2.I: e 5 Impl2\n" +
|
"Impl2.I: e 5 Impl2\n" +
|
||||||
"String is Kotlin/Native\n" +
|
"String is Kotlin/Native\n" +
|
||||||
"RO property is 42\n" +
|
"RO property is 42\n" +
|
||||||
"RW property is 239\n"
|
"RW property is 239\n" +
|
||||||
|
"enum100 = 100\n" +
|
||||||
|
"object = 42\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
task buildKonanStdlibTests(type: BuildKonanTest) {
|
task buildKonanStdlibTests(type: BuildKonanTest) {
|
||||||
|
|||||||
@@ -14,6 +14,22 @@ open class Base {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enum.
|
||||||
|
enum class Enum(val code: Int) {
|
||||||
|
ONE(1),
|
||||||
|
TWO(2),
|
||||||
|
HUNDRED(100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object.
|
||||||
|
interface Codeable {
|
||||||
|
fun asCode(): Int
|
||||||
|
}
|
||||||
|
|
||||||
|
val an_object = object : Codeable {
|
||||||
|
override fun asCode() = 42
|
||||||
|
}
|
||||||
|
|
||||||
class Child : Base() {
|
class Child : Base() {
|
||||||
override fun fooParam(arg0: String, arg1: Int) = println("Child.fooParam: $arg0 $arg1")
|
override fun fooParam(arg0: String, arg1: Int) = println("Child.fooParam: $arg0 $arg1")
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,12 @@ int main(void) {
|
|||||||
T_(Base) casted_child = { .pinned = child.pinned };
|
T_(Base) casted_child = { .pinned = child.pinned };
|
||||||
T_(I) casted_impl1 = { .pinned = impl1.pinned };
|
T_(I) casted_impl1 = { .pinned = impl1.pinned };
|
||||||
T_(I) casted_impl2 = { .pinned = impl2.pinned };
|
T_(I) casted_impl2 = { .pinned = impl2.pinned };
|
||||||
|
T_(Enum) enum1 = __ kotlin.root.Enum.HUNDRED.get();
|
||||||
|
T_(Codeable) object1 = __ kotlin.root.get_an_object();
|
||||||
|
|
||||||
const char* string = __ kotlin.root.getString();
|
const char* string = __ kotlin.root.getString();
|
||||||
|
|
||||||
|
|
||||||
__ kotlin.root.hello();
|
__ kotlin.root.hello();
|
||||||
__ kotlin.root.Base.foo(base);
|
__ kotlin.root.Base.foo(base);
|
||||||
__ kotlin.root.Base.fooParam(base, "a", 1);
|
__ kotlin.root.Base.fooParam(base, "a", 1);
|
||||||
@@ -29,11 +33,17 @@ int main(void) {
|
|||||||
__ kotlin.root.Child.set_rwProperty(child, 238);
|
__ kotlin.root.Child.set_rwProperty(child, 238);
|
||||||
printf("RW property is %d\n", __ kotlin.root.Child.get_rwProperty(child));
|
printf("RW property is %d\n", __ kotlin.root.Child.get_rwProperty(child));
|
||||||
|
|
||||||
|
printf("enum100 = %d\n", __ kotlin.root.Enum.get_code(enum1));
|
||||||
|
|
||||||
|
printf("object = %d\n", __ kotlin.root.Codeable.asCode(object1));
|
||||||
|
|
||||||
__ DisposeString(string);
|
__ DisposeString(string);
|
||||||
__ DisposeStablePointer(base.pinned);
|
__ DisposeStablePointer(base.pinned);
|
||||||
__ DisposeStablePointer(child.pinned);
|
__ DisposeStablePointer(child.pinned);
|
||||||
__ DisposeStablePointer(impl1.pinned);
|
__ DisposeStablePointer(impl1.pinned);
|
||||||
__ DisposeStablePointer(impl2.pinned);
|
__ DisposeStablePointer(impl2.pinned);
|
||||||
|
__ DisposeStablePointer(enum1.pinned);
|
||||||
|
__ DisposeStablePointer(object1.pinned);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user