Support singleton objects in C interop. (#1940)

This commit is contained in:
Nikolay Igotti
2018-08-27 14:48:29 +03:00
committed by GitHub
parent 6d8ae1650f
commit ce0b43e596
5 changed files with 58 additions and 19 deletions
@@ -28,14 +28,14 @@ import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.annotations.*
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.name.isChildOf
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.annotations.*
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isUnit
private enum class ScopeKind {
@@ -232,14 +232,22 @@ private class ExportedElement(val kind: ElementKind,
LLVMSetLinkage(bridge, LLVMLinkage.LLVMExternalLinkage)
}
isClass -> {
// Produce type getter.
val classDescriptor = declaration as ClassDescriptor
cname = "_konan_function_${owner.nextFunctionIndex()}"
val getTypeFunction = LLVMAddFunction(context.llvmModule, cname, owner.kGetTypeFuncType)!!
// Produce type getter.
val getTypeFunction = LLVMAddFunction(context.llvmModule, "${cname}_type", owner.kGetTypeFuncType)!!
val builder = LLVMCreateBuilder()!!
val bb = LLVMAppendBasicBlock(getTypeFunction, "")!!
LLVMPositionBuilderAtEnd(builder, bb)
LLVMBuildRet(builder, context.ir.getFromCurrentModule(declaration as ClassDescriptor).typeInfoPtr.llvm)
LLVMBuildRet(builder, context.ir.getFromCurrentModule(classDescriptor).typeInfoPtr.llvm)
LLVMDisposeBuilder(builder)
// Produce instance getter if needed.
if (isSingletonObject) {
generateFunction(owner.codegen, owner.kGetObjectFuncType, "${cname}_instance") {
val value = getObjectValue(context.ir.get(classDescriptor), ExceptionHandler.Caller, null)
ret(value)
}
}
}
isEnumEntry -> {
// Produce entry getter.
@@ -267,7 +275,7 @@ private class ExportedElement(val kind: ElementKind,
}
val isClass = declaration is ClassDescriptor && declaration.kind != ClassKind.ENUM_ENTRY
val isEnumEntry = declaration is ClassDescriptor && declaration.kind == ClassKind.ENUM_ENTRY
val isSingletonObject = declaration is ClassDescriptor && DescriptorUtils.isObject(declaration)
fun KotlinType.includeToSignature() = !this.isUnit()
@@ -279,7 +287,7 @@ private class ExportedElement(val kind: ElementKind,
val original = descriptor.original as FunctionDescriptor
val returned = when {
original is ConstructorDescriptor -> uniqueName(original, shortName) to original.constructedClass
// Suspend functions actually return 'Any?'.
// Suspend functions actually return 'Any?'.
original.isSuspend -> uniqueName(original, shortName) to
TypeUtils.getClassDescriptor(owner.context.builtIns.nullableAnyType)!!
else -> uniqueName(original, shortName) to TypeUtils.getClassDescriptor(original.returnType!!)!!
@@ -345,7 +353,20 @@ private class ExportedElement(val kind: ElementKind,
fun makeClassDeclaration(): String {
assert(isClass)
return "extern \"C\" ${owner.prefix}_KType* $cname(void);"
val typeGetter = "extern \"C\" ${owner.prefix}_KType* ${cname}_type(void);"
val instanceGetter = if (isSingletonObject) {
val objectClassC = owner.translateType(declaration as ClassDescriptor)
"""
|
|extern "C" KObjHeader* ${cname}_instance(KObjHeader**);
|static $objectClassC ${cname}_instance_impl(void) {
| KObjHolder result_holder;
| KObjHeader* result = ${cname}_instance(result_holder.slot());
| return $objectClassC { .pinned = CreateStablePointer(result)};
|}
""".trimMargin()
} else ""
return "$typeGetter$instanceGetter"
}
fun makeEnumEntryDeclaration(): String {
@@ -416,7 +437,7 @@ private class ExportedElement(val kind: ElementKind,
builder.append(" KObjHolder result_holder;\n")
val clazz = scope.elements[0]
assert(clazz.kind == ElementKind.TYPE)
builder.append(" KObjHeader* result = AllocInstance((const KTypeInfo*)${clazz.cname}(), result_holder.slot());\n")
builder.append(" KObjHeader* result = AllocInstance((const KTypeInfo*)${clazz.cname}_type(), result_holder.slot());\n")
args.add(0, "result")
}
if (!isVoidReturned && !isConstructor) {
@@ -669,8 +690,12 @@ internal class CAdapterGenerator(
when {
element.isFunction ->
output(element.makeFunctionPointerString(), indent)
element.isClass ->
element.isClass -> {
output("${prefix}_KType* (*_type)(void);", indent)
if (element.isSingletonObject) {
output("${translateType(element.declaration as ClassDescriptor)} (*_instance)();", indent)
}
}
element.isEnumEntry -> {
val enumClass = element.declaration.containingDeclaration as ClassDescriptor
output("${translateType(enumClass)} (*get)(); /* enum entry for ${element.name}. */", indent)
@@ -695,8 +720,11 @@ internal class CAdapterGenerator(
when {
element.isFunction ->
output("/* ${element.name} = */ ${element.cnameImpl}, ", indent)
element.isClass ->
output("/* Type for ${element.name} = */ ${element.cname}, ", indent)
element.isClass -> {
output("/* Type for ${element.name} = */ ${element.cname}_type, ", indent)
if (element.isSingletonObject)
output("/* Instance for ${element.name} = */ ${element.cname}_instance_impl, ", indent)
}
element.isEnumEntry ->
output("/* enum entry getter ${element.name} = */ ${element.cname}_impl,", indent)
// TODO: handle properties.
@@ -706,10 +706,10 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
val shared = descriptor.objectIsShared && context.config.threadsAreAllowed
val objectPtr = codegen.getObjectInstanceStorage(descriptor, shared)
val bbCurrent = currentBlock
val bbInit= basicBlock("label_init", locationInfo)
val bbExit= basicBlock("label_continue", locationInfo)
val bbInit = basicBlock("label_init", locationInfo)
val bbExit = basicBlock("label_continue", locationInfo)
val objectVal = loadSlot(objectPtr, false)
val objectInitialized= icmpUGt(ptrToInt(objectVal, codegen.intPtrType), codegen.immOneIntPtrType)
val objectInitialized = icmpUGt(ptrToInt(objectVal, codegen.intPtrType), codegen.immOneIntPtrType)
condBr(objectInitialized, bbExit, bbInit)
positionAtEnd(bbInit)
+1
View File
@@ -2896,6 +2896,7 @@ task produce_dynamic(type: DynamicKonanTest) {
"RW property is 239\n" +
"enum100 = 100\n" +
"object = 42\n" +
"singleton = I am single\n" +
"topLevel = 777 3\n"
}
@@ -45,6 +45,10 @@ val an_object = object : Codeable {
override fun asCode() = 42
}
object Singleton {
override fun toString() = "I am single"
}
class Child : Base() {
override fun fooParam(arg0: String, arg1: Int) = println("Child.fooParam: $arg0 $arg1")
@@ -15,8 +15,10 @@ int main(void) {
T_(I) casted_impl2 = { .pinned = impl2.pinned };
T_(Enum) enum1 = __ kotlin.root.Enum.HUNDRED.get();
T_(Codeable) object1 = __ kotlin.root.get_an_object();
T_(Singleton) singleton = __ kotlin.root.Singleton._instance();
const char* string = __ kotlin.root.getString();
const char* string1 = __ kotlin.root.getString();
const char* string2 = __ kotlin.root.Singleton.toString(singleton);
__ kotlin.root.hello();
__ kotlin.root.Base.foo(base);
@@ -26,7 +28,7 @@ int main(void) {
__ kotlin.root.I.foo(casted_impl1, "d", 4, casted_impl1);
__ kotlin.root.I.foo(casted_impl2, "e", 5, casted_impl2);
printf("String is %s\n", string);
printf("String is %s\n", string1);
printf("RO property is %d\n", __ kotlin.root.Child.get_roProperty(child));
__ kotlin.root.Child.set_rwProperty(child, 238);
@@ -36,13 +38,17 @@ int main(void) {
printf("object = %d\n", __ kotlin.root.Codeable.asCode(object1));
printf("singleton = %s\n", string2);
topLevelFunctionVoidFromC(42, 0);
__ kotlin.root.topLevelFunctionVoid(42, 0);
printf("topLevel = %d %d\n", topLevelFunctionFromC(780, 3), __ kotlin.root.topLevelFunctionFromCShort(5, 2));
__ kotlin.root.useInlineClasses(42, "bar", base);
__ DisposeString(string);
__ DisposeStablePointer(singleton.pinned);
__ DisposeString(string1);
__ DisposeString(string2);
__ DisposeStablePointer(base.pinned);
__ DisposeStablePointer(child.pinned);
__ DisposeStablePointer(impl1.pinned);