Runtime ABI (#1097)
This commit is contained in:
+49
-19
@@ -163,10 +163,6 @@ private class ExportedElement(val kind: ElementKind,
|
|||||||
val params = ArrayList(original.explicitParameters.map {
|
val params = ArrayList(original.explicitParameters.map {
|
||||||
owner.translateName(it.name.asString()) to TypeUtils.getClassDescriptor(it.type)!!
|
owner.translateName(it.name.asString()) to TypeUtils.getClassDescriptor(it.type)!!
|
||||||
})
|
})
|
||||||
if (original is ConstructorDescriptor) {
|
|
||||||
// Remove `this` parameter from the constructor.
|
|
||||||
params.removeAt(0)
|
|
||||||
}
|
|
||||||
return listOf(returned) + params
|
return listOf(returned) + params
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +182,7 @@ private class ExportedElement(val kind: ElementKind,
|
|||||||
owner.translateTypeBridge(TypeUtils.getClassDescriptor(it.type)!!)
|
owner.translateTypeBridge(TypeUtils.getClassDescriptor(it.type)!!)
|
||||||
})
|
})
|
||||||
if (owner.isMappedToReference(returnedClass) || owner.isMappedToString(returnedClass)) {
|
if (owner.isMappedToReference(returnedClass) || owner.isMappedToString(returnedClass)) {
|
||||||
params += "ObjHeader**"
|
params += "KObjHeader**"
|
||||||
}
|
}
|
||||||
return listOf(owner.translateTypeBridge(returnedClass)) + params
|
return listOf(owner.translateTypeBridge(returnedClass)) + params
|
||||||
}
|
}
|
||||||
@@ -221,14 +217,14 @@ private class ExportedElement(val kind: ElementKind,
|
|||||||
return when {
|
return when {
|
||||||
fqName == "kotlin.String" ->
|
fqName == "kotlin.String" ->
|
||||||
if (direction == Direction.C_TO_KOTLIN) {
|
if (direction == Direction.C_TO_KOTLIN) {
|
||||||
builder.append(" ObjHolder ${name}_holder;\n")
|
builder.append(" KObjHolder ${name}_holder;\n")
|
||||||
"CreateStringFromCString($name, ${name}_holder.slot())"
|
"CreateStringFromCString($name, ${name}_holder.slot())"
|
||||||
} else {
|
} else {
|
||||||
"CreateCStringFromString($name)"
|
"CreateCStringFromString($name)"
|
||||||
}
|
}
|
||||||
owner.isMappedToReference(clazz) ->
|
owner.isMappedToReference(clazz) ->
|
||||||
if (direction == Direction.C_TO_KOTLIN) {
|
if (direction == Direction.C_TO_KOTLIN) {
|
||||||
builder.append(" ObjHolder ${name}_holder2;\n")
|
builder.append(" KObjHolder ${name}_holder2;\n")
|
||||||
"DerefStablePointer(${name}.pinned, ${name}_holder2.slot())"
|
"DerefStablePointer(${name}.pinned, ${name}_holder2.slot())"
|
||||||
} else {
|
} else {
|
||||||
"((${owner.translateType(clazz)}){ .pinned = CreateStablePointer(${name})})"
|
"((${owner.translateType(clazz)}){ .pinned = CreateStablePointer(${name})})"
|
||||||
@@ -247,15 +243,17 @@ private class ExportedElement(val kind: ElementKind,
|
|||||||
val isConstructor = declaration is ConstructorDescriptor
|
val isConstructor = declaration is ConstructorDescriptor
|
||||||
val isObjectReturned = !isConstructor && owner.isMappedToReference(cfunction[0].second)
|
val isObjectReturned = !isConstructor && owner.isMappedToReference(cfunction[0].second)
|
||||||
val isStringReturned = owner.isMappedToString(cfunction[0].second)
|
val isStringReturned = owner.isMappedToString(cfunction[0].second)
|
||||||
|
// TODO: do we really need that in every function?
|
||||||
|
builder.append(" Kotlin_initRuntimeIfNeeded();\n")
|
||||||
if (isObjectReturned || isStringReturned) {
|
if (isObjectReturned || isStringReturned) {
|
||||||
builder.append(" ObjHolder result_holder;\n")
|
builder.append(" KObjHolder result_holder;\n")
|
||||||
args += "result_holder.slot()"
|
args += "result_holder.slot()"
|
||||||
}
|
}
|
||||||
if (isConstructor) {
|
if (isConstructor) {
|
||||||
builder.append(" ObjHolder result_holder;\n")
|
builder.append(" KObjHolder result_holder;\n")
|
||||||
val clazz = scope.elements[0]
|
val clazz = scope.elements[0]
|
||||||
assert(clazz.kind == ElementKind.TYPE)
|
assert(clazz.kind == ElementKind.TYPE)
|
||||||
builder.append(" KRef result = AllocInstance((const TypeInfo*)${clazz.cname}(), result_holder.slot());\n")
|
builder.append(" KObjHeader* result = AllocInstance((const KTypeInfo*)${clazz.cname}(), result_holder.slot());\n")
|
||||||
args.add(0, "result")
|
args.add(0, "result")
|
||||||
}
|
}
|
||||||
if (!isVoidReturned && !isConstructor) {
|
if (!isVoidReturned && !isConstructor) {
|
||||||
@@ -476,19 +474,51 @@ internal class CAdapterGenerator(val context: Context,
|
|||||||
|
|
||||||
outputStreamWriter = PrintWriter(File(".", "${prefix}_api.cpp").outputStream())
|
outputStreamWriter = PrintWriter(File(".", "${prefix}_api.cpp").outputStream())
|
||||||
output("#include \"${prefix}_api.h\"")
|
output("#include \"${prefix}_api.h\"")
|
||||||
output("#include \"KString.h\"")
|
|
||||||
output("#include \"Memory.h\"")
|
|
||||||
output("#include \"Types.h\"")
|
|
||||||
output("""
|
output("""
|
||||||
|
|struct KObjHeader;
|
||||||
|
|typedef struct KObjHeader KObjHeader;
|
||||||
|
|struct KTypeInfo;
|
||||||
|
|typedef struct KTypeInfo KTypeInfo;
|
||||||
|
|
|
||||||
|
|#define RUNTIME_NOTHROW __attribute__((nothrow))
|
||||||
|
|#define RUNTIME_USED __attribute__((used))
|
||||||
|
|
|
||||||
|
|void SetRef(KObjHeader**, const KObjHeader*) RUNTIME_NOTHROW;
|
||||||
|
|void UpdateRef(KObjHeader**, const KObjHeader*) RUNTIME_NOTHROW;
|
||||||
|
|KObjHeader* AllocInstance(const KTypeInfo*, KObjHeader**) RUNTIME_NOTHROW;
|
||||||
|
|KObjHeader* DerefStablePointer(void*, KObjHeader**) RUNTIME_NOTHROW;
|
||||||
|
|void* CreateStablePointer(KObjHeader*) RUNTIME_NOTHROW;
|
||||||
|
|void DisposeStablePointer(void*) RUNTIME_NOTHROW;
|
||||||
|
|int IsInstance(const KObjHeader*, const KTypeInfo*) RUNTIME_NOTHROW;
|
||||||
|
|void Kotlin_initRuntimeIfNeeded();
|
||||||
|
|
|
||||||
|
|KObjHeader* CreateStringFromCString(const char*, KObjHeader**);
|
||||||
|
|char* CreateCStringFromString(const KObjHeader*);
|
||||||
|
|void DisposeCString(char* cstring);
|
||||||
|
|
|
||||||
|
|class KObjHolder {
|
||||||
|
|public:
|
||||||
|
| KObjHolder() : obj_(nullptr) {}
|
||||||
|
| explicit KObjHolder(const KObjHeader* obj) {
|
||||||
|
| SetRef(&obj_, obj);
|
||||||
|
| }
|
||||||
|
| ~KObjHolder() {
|
||||||
|
| UpdateRef(&obj_, nullptr);
|
||||||
|
| }
|
||||||
|
| KObjHeader* obj() { return obj_; }
|
||||||
|
| KObjHeader** slot() { return &obj_; }
|
||||||
|
| private:
|
||||||
|
| KObjHeader* obj_;
|
||||||
|
|};
|
||||||
|static void DisposeStablePointerImpl(${prefix}_KNativePtr ptr) {
|
|static void DisposeStablePointerImpl(${prefix}_KNativePtr ptr) {
|
||||||
| DisposeStablePointer(ptr);
|
| DisposeStablePointer(ptr);
|
||||||
|}
|
|}
|
||||||
|static void DisposeStringImpl(char* ptr) {
|
|static void DisposeStringImpl(char* ptr) {
|
||||||
| if (ptr) konan::free(ptr);
|
| DisposeCString(ptr);
|
||||||
|}
|
|}
|
||||||
|static ${prefix}_KBoolean IsInstanceImpl(${prefix}_KNativePtr ref, const ${prefix}_KType* type) {
|
|static ${prefix}_KBoolean IsInstanceImpl(${prefix}_KNativePtr ref, const ${prefix}_KType* type) {
|
||||||
| ObjHolder holder;
|
| KObjHolder holder;
|
||||||
| return IsInstance(DerefStablePointer(ref, holder.slot()), (const TypeInfo*)type);
|
| return IsInstance(DerefStablePointer(ref, holder.slot()), (const KTypeInfo*)type);
|
||||||
|}
|
|}
|
||||||
""".trimMargin())
|
""".trimMargin())
|
||||||
makeScopeDefinitions(top, DefinitionKind.C_SOURCE_DECLARATION, 0)
|
makeScopeDefinitions(top, DefinitionKind.C_SOURCE_DECLARATION, 0)
|
||||||
@@ -498,7 +528,7 @@ internal class CAdapterGenerator(val context: Context,
|
|||||||
output(".IsInstance = IsInstanceImpl,", 1)
|
output(".IsInstance = IsInstanceImpl,", 1)
|
||||||
makeScopeDefinitions(top, DefinitionKind.C_SOURCE_STRUCT, 1)
|
makeScopeDefinitions(top, DefinitionKind.C_SOURCE_STRUCT, 1)
|
||||||
output("};")
|
output("};")
|
||||||
output("${prefix}_ExportedSymbols* ${prefix}_symbols() { return &__konan_symbols;}")
|
output("RUNTIME_USED ${prefix}_ExportedSymbols* ${prefix}_symbols() { return &__konan_symbols;}")
|
||||||
outputStreamWriter.close()
|
outputStreamWriter.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,9 +570,9 @@ internal class CAdapterGenerator(val context: Context,
|
|||||||
val fqName = clazz.fqNameSafe.asString()
|
val fqName = clazz.fqNameSafe.asString()
|
||||||
return when {
|
return when {
|
||||||
clazz.isUnit() -> "void" to "void"
|
clazz.isUnit() -> "void" to "void"
|
||||||
fqName == "kotlin.String" -> "const char*" to "KRef"
|
fqName == "kotlin.String" -> "const char*" to "KObjHeader*"
|
||||||
primitiveTypeMapping.contains(fqName) -> primitiveTypeMapping[fqName]!! to primitiveTypeMapping[fqName]!!
|
primitiveTypeMapping.contains(fqName) -> primitiveTypeMapping[fqName]!! to primitiveTypeMapping[fqName]!!
|
||||||
else -> "${prefix}_kref_${translateTypeFqName(clazz.fqNameSafe.asString())}" to "KRef"
|
else -> "${prefix}_kref_${translateTypeFqName(clazz.fqNameSafe.asString())}" to "KObjHeader*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -704,6 +704,10 @@ char* CreateCStringFromString(KConstRef kref) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisposeCString(char* cstring) {
|
||||||
|
if (cstring) konan::free(cstring);
|
||||||
|
}
|
||||||
|
|
||||||
// String.kt
|
// String.kt
|
||||||
KInt Kotlin_String_compareTo(KString thiz, KString other) {
|
KInt Kotlin_String_compareTo(KString thiz, KString other) {
|
||||||
int result = memcmp(
|
int result = memcmp(
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ extern "C" {
|
|||||||
OBJ_GETTER(CreateStringFromCString, const char* cstring);
|
OBJ_GETTER(CreateStringFromCString, const char* cstring);
|
||||||
OBJ_GETTER(CreateStringFromUtf8, const char* utf8, uint32_t size);
|
OBJ_GETTER(CreateStringFromUtf8, const char* utf8, uint32_t size);
|
||||||
char* CreateCStringFromString(KConstRef kstring);
|
char* CreateCStringFromString(KConstRef kstring);
|
||||||
|
void DisposeCString(char* cstring);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -391,7 +391,7 @@ bool ClearSubgraphReferences(ObjHeader* root, bool checked) RUNTIME_NOTHROW;
|
|||||||
// Creates stable pointer out of the object.
|
// Creates stable pointer out of the object.
|
||||||
void* CreateStablePointer(ObjHeader* obj) RUNTIME_NOTHROW;
|
void* CreateStablePointer(ObjHeader* obj) RUNTIME_NOTHROW;
|
||||||
// Disposes stable pointer to the object.
|
// Disposes stable pointer to the object.
|
||||||
void DisposeStablePointer(void* pointer) RUNTIME_NOTHROW;;
|
void DisposeStablePointer(void* pointer) RUNTIME_NOTHROW;
|
||||||
// Translate stable pointer to object reference.
|
// Translate stable pointer to object reference.
|
||||||
OBJ_GETTER(DerefStablePointer, void*) RUNTIME_NOTHROW;
|
OBJ_GETTER(DerefStablePointer, void*) RUNTIME_NOTHROW;
|
||||||
// Move stable pointer ownership.
|
// Move stable pointer ownership.
|
||||||
|
|||||||
Reference in New Issue
Block a user