diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index fd2fd3b83d8..043c2f14201 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -17,6 +17,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { // TODO: remove, to make CodeGenerator descriptor-agnostic. var constructedClass: ClassDescriptor? = null val vars = VariableManager(this) + var returnSlot: LLVMValueRef? = null fun prologue(descriptor: FunctionDescriptor) { prologue(llvmFunction(descriptor), @@ -28,8 +29,11 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { fun prologue(function:LLVMValueRef, returnType:LLVMTypeRef) { assert(returns.size == 0) - assert(this.function != function) + + if (isObjectType(returnType)) { + this.returnSlot = LLVMGetParam(function, numParameters(function.type) - 1) + } this.function = function this.returnType = returnType this.constructedClass = null @@ -48,11 +52,15 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { when { returnType == voidType -> { vars.releaseVars() + assert(returnSlot == null) LLVMBuildRetVoid(builder) } returns.size > 0 -> { val returnPhi = phi(returnType!!) addPhiIncoming(returnPhi, *returns.toList().toTypedArray()) + if (returnSlot != null) { + updateLocalRef(returnPhi, returnSlot!!) + } vars.releaseVars() LLVMBuildRet(builder, returnPhi) } @@ -63,6 +71,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { returns.clear() vars.clear() + returnSlot = null } private var prologueBb: LLVMBasicBlockRef? = null @@ -103,6 +112,11 @@ internal class CodeGenerator(override val context: Context) : ContextUtils { fun load(value: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildLoad(builder, value, name)!! fun store(value: LLVMValueRef, ptr: LLVMValueRef): LLVMValueRef = LLVMBuildStore(builder, value, ptr)!! + fun updateLocalRef(value: LLVMValueRef, address: LLVMValueRef, ignoreOld: Boolean = false) { + call(if (ignoreOld) context.llvm.setLocalRefFunction else context.llvm.updateLocalRefFunction, + listOf(address, value)) + } + fun isConst(value: LLVMValueRef): Boolean = (LLVMIsConstant(value) == 1) //-------------------------------------------------------------------------// diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index 8c885b6c77e..9db8b4440b6 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt @@ -221,6 +221,8 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) { val allocInstanceFunction = importRtFunction("AllocInstance") val initInstanceFunction = importRtFunction("InitInstance") val allocArrayFunction = importRtFunction("AllocArrayInstance") + val setLocalRefFunction = importRtFunction("SetLocalRef") + val updateLocalRefFunction = importRtFunction("UpdateLocalRef") val setArrayFunction = importRtFunction("Kotlin_Array_set") val copyImplArrayFunction = importRtFunction("Kotlin_Array_copyImpl") val lookupFieldOffset = importRtFunction("LookupFieldOffset") diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 02c9246d3f2..b7d5ceb1eaa 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -429,10 +429,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid } }) } - - codegen.ret(thisPtr) } + codegen.ret(null) codegen.epilogue() context.log("visitConstructor : ${ir2string(constructorDeclaration)}") } @@ -553,11 +552,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid } override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) { - if (declaration == null) { - codegen.ret(value) - return - } - if (target == declaration.descriptor) { + if (declaration == null || target == declaration.descriptor) { codegen.ret(value) } else { super.genReturn(target, value) @@ -582,9 +577,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid private fun bindParameters(descriptor: FunctionDescriptor?): Map { if (descriptor == null) return emptyMap() val paramDescriptors = descriptor.allValueParameters - - assert(paramDescriptors.size == codegen.countParams(descriptor)) - return paramDescriptors.mapIndexed { i, paramDescriptor -> val param = codegen.param(descriptor, i) assert(codegen.getLLVMType(paramDescriptor.type) == param.type) @@ -757,7 +749,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val initFunction = value.descriptor.constructors.first { it.valueParameters.size == 0 } val ctor = codegen.llvmFunction(initFunction) val args = listOf(objectPtr, typeInfo, allocHint, ctor) - val newValue = currentCodeContext.genCall(context.llvm.initInstanceFunction, args) + val newValue = call(context.llvm.initInstanceFunction, args) codegen.br(bbExit) codegen.positionAtEnd(bbExit) @@ -846,7 +838,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid } } - //-------------------------------------------------------------------------// private fun evaluateVararg(value: IrVararg): LLVMValueRef? { @@ -879,14 +870,13 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val typeInfo = codegen.typeInfoValue(value.type)!! val arrayCreationArgs = listOf(typeInfo, kImmInt32One, finalLength) - val array = currentCodeContext.genCall(context.llvm.allocArrayFunction, arrayCreationArgs) - + val array = call(context.llvm.allocArrayFunction, arrayCreationArgs) elements.fold(kImmZero) { sum, (exp, size, isArray) -> if (!isArray) { - currentCodeContext.genCall(context.llvm.setArrayFunction, listOf(array, sum, exp)) + call(context.llvm.setArrayFunction, listOf(array, sum, exp)) return@fold codegen.plus(sum, kImmOne) } else { - currentCodeContext.genCall(context.llvm.copyImplArrayFunction, listOf(exp, kImmZero, array, sum, size!!)) + call(context.llvm.copyImplArrayFunction, listOf(exp, kImmZero, array, sum, size!!)) return@fold codegen.plus(sum, size) } } @@ -920,7 +910,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val toStringDescriptor = getToString(it.type) val string = if (KotlinBuiltIns.isString(it.type)) evaluationResult else evaluateSimpleFunctionCall(toStringDescriptor, listOf(evaluationResult)) - val length = currentCodeContext.genCall(codegen.llvmFunction(kStringLength!!), listOf(string)) + val length = call(codegen.llvmFunction(kStringLength!!), listOf(string)) return@map Element(string, length, -1) } } @@ -933,12 +923,12 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val constructor = kStringBuilder!!.constructors .firstOrNull { it -> it.valueParameters.size == 1 && KotlinBuiltIns.isInt(it.valueParameters[0].type) }!! - val stringBuilderObjPtr = currentCodeContext.genCall(context.llvm.allocInstanceFunction, + val stringBuilderObj = call(context.llvm.allocInstanceFunction, listOf(codegen.typeInfoValue(kStringBuilder.defaultType)!!, kImmOne)) - val stringBuilderObj = currentCodeContext.genCall(codegen.llvmFunction(constructor), listOf(stringBuilderObjPtr, totalLength)) + call(codegen.llvmFunction(constructor), listOf(stringBuilderObj, totalLength)) stringsWithLengths.fold(stringBuilderObj) { sum, (string, _, _) -> - currentCodeContext.genCall(codegen.llvmFunction(kStringBuilderAppendStringFn!!), listOf(sum, string)) + call(codegen.llvmFunction(kStringBuilderAppendStringFn!!), listOf(sum, string)) return@fold sum } @@ -1390,7 +1380,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val srcArg = evaluateExpression(value.argument)!! // Evaluate src expression. val srcObjInfoPtr = codegen.bitcast(codegen.kObjHeaderPtr, srcArg) // Cast src to ObjInfoPtr. val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list. - currentCodeContext.genCall(context.llvm.checkInstanceFunction, args) // Check if dst is subclass of src. + call(context.llvm.checkInstanceFunction, args) // Check if dst is subclass of src. return srcArg } @@ -1431,9 +1421,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val srcObjInfoPtr = codegen.bitcast(codegen.kObjHeaderPtr, obj) // Cast src to ObjInfoPtr. val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list. - val result = currentCodeContext.genCall( // Check if dst is subclass of src. - context.llvm.isInstanceFunction, args) - + val result = call(context.llvm.isInstanceFunction, args) // Check if dst is subclass of src. return LLVMBuildTrunc(codegen.builder, result, kInt1, "")!! // Truncate result to boolean } @@ -1783,14 +1771,15 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val thisValue = if (containingClass.isArray) { assert(args.size == 1 && args[0].type == int32Type) val allocArrayInstanceArgs = listOf(typeInfo, allocHint, args[0]) - currentCodeContext.genCall(context.llvm.allocArrayFunction, allocArrayInstanceArgs) + call(context.llvm.allocArrayFunction, allocArrayInstanceArgs) } else { - currentCodeContext.genCall(context.llvm.allocInstanceFunction, listOf(typeInfo, allocHint)) + call(context.llvm.allocInstanceFunction, listOf(typeInfo, allocHint)) } val constructorParams: MutableList = mutableListOf() constructorParams += thisValue constructorParams += args - return evaluateSimpleFunctionCall(callee.descriptor as FunctionDescriptor, constructorParams) + evaluateSimpleFunctionCall(callee.descriptor as FunctionDescriptor, constructorParams) + return thisValue } } @@ -1900,8 +1889,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val typeInfoPtr = codegen.bitcast(codegen.kTypeInfoPtr, typeInfoI8Ptr) // Cast TypeInfo (i8*) to TypeInfo*. val methodHash = codegen.functionHash(descriptor) // Calculate hash of the method to be invoked val lookupArgs = listOf(typeInfoPtr, methodHash) // Prepare args for lookup - val llvmMethod = currentCodeContext.genCall( - context.llvm.lookupOpenMethodFunction, + val llvmMethod = call(context.llvm.lookupOpenMethodFunction, lookupArgs) // Get method ptr to be invoked val functionPtrType = pointerType(codegen.getLlvmFunctionType(descriptor)) // Construct type of the method to be invoked @@ -1916,13 +1904,24 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid // In such case it would be possible to check that all args are available and in the correct order. // However, it currently requires some refactoring to be performed. private fun call(descriptor: FunctionDescriptor, function: LLVMValueRef, args: List): LLVMValueRef { - val result = currentCodeContext.genCall(function, args) + val result = call(function, args) if (descriptor.returnType?.isNothing() == true) { codegen.unreachable() } return result } + private fun call(function: LLVMValueRef, args: List): LLVMValueRef { + if (codegen.isObjectReturn(function.type)) { + // If function returns an object - create slot for the returned value. + // This allows appropriate rootset accounting by just looking on stack slots. + val resultSlot = codegen.vars.createAnonymousSlot() + return currentCodeContext.genCall(function, args + resultSlot) + } else { + return currentCodeContext.genCall(function, args) + } + } + //-------------------------------------------------------------------------// fun delegatingConstructorCall(descriptor: ClassConstructorDescriptor, args: List): LLVMValueRef { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt index f235ef37f37..da72c7b1e9c 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt @@ -4,6 +4,7 @@ import kotlinx.cinterop.* import llvm.* import org.jetbrains.kotlin.backend.konan.descriptors.allValueParameters import org.jetbrains.kotlin.backend.konan.KonanPlatform +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor internal val LLVMValueRef.type: LLVMTypeRef @@ -141,10 +142,14 @@ internal fun structType(types: List): LLVMTypeRef = memScoped { LLVMStructType(allocArrayOf(types)[0].ptr, types.size, 0)!! } +internal fun ContextUtils.isObjectType(type: LLVMTypeRef) : Boolean { + return type == kObjHeaderPtr || type == kArrayHeaderPtr +} + internal fun ContextUtils.getLlvmFunctionType(function: FunctionDescriptor): LLVMTypeRef { - val returnType = getLLVMType(function.returnType!!) - val params = function.allValueParameters - val paramTypes = params.map { getLLVMType(it.type) } + val returnType = if (function is ConstructorDescriptor) voidType else getLLVMType(function.returnType!!) + val paramTypes = ArrayList(function.allValueParameters.map { getLLVMType(it.type) }) + if (isObjectType(returnType)) paramTypes.add(kObjHeaderPtrPtr) memScoped { val paramTypesPtr = allocArrayOf(paramTypes)[0].ptr @@ -152,6 +157,17 @@ internal fun ContextUtils.getLlvmFunctionType(function: FunctionDescriptor): LLV } } +internal fun ContextUtils.numParameters(functionType: LLVMTypeRef) : Int { + // Note that type is usually function pointer, so we have to dereference it. + return LLVMCountParamTypes(LLVMGetElementType(functionType))!! +} + +internal fun ContextUtils.isObjectReturn(functionType: LLVMTypeRef) : Boolean { + // Note that type is usually function pointer, so we have to dereference it. + val returnType = LLVMGetReturnType(LLVMGetElementType(functionType))!! + return isObjectType(returnType) +} + /** * Reads [size] bytes contained in this array. */ @@ -197,3 +213,8 @@ fun llvm2string(value: LLVMValueRef?): String { return LLVMPrintValueToString(value)!!.asCString().toString() } +fun llvmtype2string(type: LLVMTypeRef?): String { + if (type == null) return "" + return LLVMPrintTypeToString(type)!!.asCString().toString() +} + diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/VariableManager.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/VariableManager.kt index 3cf7c9155cb..e2891a26d7e 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/VariableManager.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/VariableManager.kt @@ -60,7 +60,7 @@ internal class VariableManager(val codegen: CodeGenerator) { // TODO: fix, due to the bug in frontend, we shall always create stack slot for variable now. // Note that we always create slot for object references for memory management. val descriptor = scoped.first - if (descriptor.isVar() || isObjectType(codegen.getLLVMType(descriptor.type)) || true) { + if (descriptor.isVar() || codegen.isObjectType(codegen.getLLVMType(descriptor.type)) || true) { return createMutable(scoped, value) } else { return createImmutable(scoped, value!!) @@ -75,7 +75,7 @@ internal class VariableManager(val codegen: CodeGenerator) { val slot = codegen.alloca(type, descriptor.name.asString()) if (value != null) codegen.store(value, slot) - variables.add(SlotRecord(slot, isObjectType(type))) + variables.add(SlotRecord(slot, codegen.isObjectType(type))) descriptors[scoped] = index return index } @@ -85,12 +85,18 @@ internal class VariableManager(val codegen: CodeGenerator) { return createAnonymousMutable(codegen.getLLVMType(type), value) } + // Think of slot reuse. + fun createAnonymousSlot(value: LLVMValueRef? = null) : LLVMValueRef { + val index = createAnonymousMutable(codegen.kObjHeaderPtr, value) + return addressOf(index) + } + fun createAnonymousMutable(type: LLVMTypeRef, value: LLVMValueRef? = null) : Int { val index = variables.size val slot = codegen.alloca(type) if (value != null) codegen.store(value, slot) - variables.add(SlotRecord(slot, isObjectType(type))) + variables.add(SlotRecord(slot, codegen.isObjectType(type))) return index } @@ -118,8 +124,4 @@ internal class VariableManager(val codegen: CodeGenerator) { fun store(value: LLVMValueRef, index: Int) { variables[index].store(value) } - - private fun isObjectType(type: LLVMTypeRef) : Boolean { - return type == codegen.kObjHeaderPtr || type == codegen.kArrayHeaderPtr - } } diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index 588b6ca50d3..6d2d7174d0c 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -108,6 +108,7 @@ abstract class KonanTest extends DefaultTask { } } +// Please do not use this framework anymore! class UnitKonanTest extends KonanTest { void compileTest(File sourceS, File runtimeS, File stdlibKtBc, File exe) { def testC = sourceS.absolutePath.replace(".kt.S", "-test.c") @@ -120,6 +121,11 @@ class UnitKonanTest extends KonanTest { args argList } } + + @TaskAction + void executeTest() { + // Do nothing, unit tests go away. + } } class RunKonanTest extends KonanTest { diff --git a/runtime/src/launcher/cpp/launcher.cpp b/runtime/src/launcher/cpp/launcher.cpp index 1ade5733872..5cb8451e5ba 100644 --- a/runtime/src/launcher/cpp/launcher.cpp +++ b/runtime/src/launcher/cpp/launcher.cpp @@ -5,16 +5,15 @@ //--- Setup args --------------------------------------------------------------// -ObjHeader* setupArgs(int argc, char** argv) { - // The count is one less, because we skip argv[0] which is the binary name. - ObjHeader* args = AllocArrayInstance(theArrayTypeInfo, SCOPE_GLOBAL, argc-1); - - for (int i = 0; i < argc-1; i++) { - Kotlin_Array_set(args, i, AllocStringInstance( - SCOPE_GLOBAL, argv[i+1], strlen(argv[i+1]) )); - } - - return args; +OBJ_GETTER(setupArgs, int argc, char** argv) { + // The count is one less, because we skip argv[0] which is the binary name. + AllocArrayInstance(theArrayTypeInfo, SCOPE_GLOBAL, argc - 1, OBJ_RESULT); + ArrayHeader* array = (*OBJ_RESULT)->array(); + for (int index = 0; index < argc - 1; index++) { + AllocStringInstance(SCOPE_GLOBAL, argv[index + 1], strlen(argv[index + 1]), + ArrayAddressOfElementAt(array, index)); + } + RETURN_OBJ_RESULT(); } //--- main --------------------------------------------------------------------// @@ -26,9 +25,11 @@ int main(int argc, char** argv) { InitMemory(); InitGlobalVariables(); - ObjHeader* args = setupArgs(argc, argv); - - Konan_start(args); + { + ObjHolder args; + setupArgs(argc, argv, args.slot()); + Konan_start(args.obj()); + } // Yes, we have to follow Java convention and return zero. return 0; diff --git a/runtime/src/main/cpp/Arrays.cpp b/runtime/src/main/cpp/Arrays.cpp index ec8794dd5f1..8c9fa0a343e 100644 --- a/runtime/src/main/cpp/Arrays.cpp +++ b/runtime/src/main/cpp/Arrays.cpp @@ -12,12 +12,12 @@ extern "C" { // TODO: those must be compiler intrinsics afterwards. // Array.kt -KRef Kotlin_Array_get(KConstRef thiz, KInt index) { +OBJ_GETTER(Kotlin_Array_get, KConstRef thiz, KInt index) { const ArrayHeader* array = thiz->array(); if (static_cast(index) >= array->count_) { ThrowArrayIndexOutOfBoundsException(); } - return *ArrayAddressOfElementAt(array, index); + RETURN_OBJ(*ArrayAddressOfElementAt(array, index)); } void Kotlin_Array_set(KRef thiz, KInt index, KConstRef value) { @@ -25,10 +25,10 @@ void Kotlin_Array_set(KRef thiz, KInt index, KConstRef value) { if (static_cast(index) >= array->count_) { ThrowArrayIndexOutOfBoundsException(); } - *ArrayAddressOfElementAt(array, index) = value; + UpdateGlobalRef(ArrayAddressOfElementAt(array, index), value); } -KRef Kotlin_Array_clone(KConstRef thiz) { +OBJ_GETTER(Kotlin_Array_clone, KConstRef thiz) { const ArrayHeader* array = thiz->array(); ArrayHeader* result = ArrayContainer( array->type_info(), array->count_).GetPlace(); @@ -36,7 +36,7 @@ KRef Kotlin_Array_clone(KConstRef thiz) { ArrayAddressOfElementAt(result, 0), ArrayAddressOfElementAt(array, 0), ArrayDataSizeBytes(array)); - return result->obj(); + RETURN_OBJ(result->obj()); } KInt Kotlin_Array_getArrayLength(KConstRef thiz) { @@ -85,7 +85,7 @@ void Kotlin_ByteArray_set(KRef thiz, KInt index, KByte value) { *ByteArrayAddressOfElementAt(array, index) = value; } -KRef Kotlin_ByteArray_clone(KConstRef thiz) { +OBJ_GETTER(Kotlin_ByteArray_clone, KConstRef thiz) { const ArrayHeader* array = thiz->array(); ArrayHeader* result = ArrayContainer( theByteArrayTypeInfo, array->count_).GetPlace(); @@ -93,7 +93,7 @@ KRef Kotlin_ByteArray_clone(KConstRef thiz) { ByteArrayAddressOfElementAt(result, 0), ByteArrayAddressOfElementAt(array, 0), ArrayDataSizeBytes(array)); - return result->obj(); + RETURN_OBJ(result->obj()); } KInt Kotlin_ByteArray_getArrayLength(KConstRef thiz) { @@ -117,7 +117,7 @@ void Kotlin_CharArray_set(KRef thiz, KInt index, KChar value) { *PrimitiveArrayAddressOfElementAt(array, index) = value; } -KRef Kotlin_CharArray_clone(KConstRef thiz) { +OBJ_GETTER(Kotlin_CharArray_clone, KConstRef thiz) { const ArrayHeader* array = thiz->array(); ArrayHeader* result = ArrayContainer( theCharArrayTypeInfo, array->count_).GetPlace(); @@ -125,10 +125,10 @@ KRef Kotlin_CharArray_clone(KConstRef thiz) { PrimitiveArrayAddressOfElementAt(result, 0), PrimitiveArrayAddressOfElementAt(array, 0), ArrayDataSizeBytes(array)); - return result->obj(); + RETURN_OBJ(result->obj()); } -KRef Kotlin_CharArray_copyOf(KConstRef thiz, KInt newSize) { +OBJ_GETTER(Kotlin_CharArray_copyOf, KConstRef thiz, KInt newSize) { const ArrayHeader* array = thiz->array(); ArrayHeader* result = ArrayContainer( theCharArrayTypeInfo, newSize).GetPlace(); @@ -137,7 +137,7 @@ KRef Kotlin_CharArray_copyOf(KConstRef thiz, KInt newSize) { PrimitiveArrayAddressOfElementAt(result, 0), PrimitiveArrayAddressOfElementAt(array, 0), toCopy * sizeof(KChar)); - return result->obj(); + RETURN_OBJ(result->obj()); } KInt Kotlin_CharArray_getArrayLength(KConstRef thiz) { @@ -161,7 +161,7 @@ void Kotlin_ShortArray_set(KRef thiz, KInt index, KShort value) { *PrimitiveArrayAddressOfElementAt(array, index) = value; } -KRef Kotlin_ShortArray_clone(KConstRef thiz) { +OBJ_GETTER(Kotlin_ShortArray_clone, KConstRef thiz) { const ArrayHeader* array = thiz->array(); ArrayHeader* result = ArrayContainer( theShortArrayTypeInfo, array->count_).GetPlace(); @@ -169,7 +169,7 @@ KRef Kotlin_ShortArray_clone(KConstRef thiz) { PrimitiveArrayAddressOfElementAt(result, 0), PrimitiveArrayAddressOfElementAt(array, 0), ArrayDataSizeBytes(array)); - return result->obj(); + RETURN_OBJ(result->obj()); } KInt Kotlin_ShortArray_getArrayLength(KConstRef thiz) { @@ -193,7 +193,7 @@ void Kotlin_IntArray_set(KRef thiz, KInt index, KInt value) { *PrimitiveArrayAddressOfElementAt(array, index) = value; } -KRef Kotlin_IntArray_clone(KConstRef thiz) { +OBJ_GETTER(Kotlin_IntArray_clone, KConstRef thiz) { const ArrayHeader* array = thiz->array(); ArrayHeader* result = ArrayContainer( theIntArrayTypeInfo, array->count_).GetPlace(); @@ -201,7 +201,7 @@ KRef Kotlin_IntArray_clone(KConstRef thiz) { PrimitiveArrayAddressOfElementAt(result, 0), PrimitiveArrayAddressOfElementAt(array, 0), ArrayDataSizeBytes(array)); - return result->obj(); + RETURN_OBJ(result->obj()); } KInt Kotlin_IntArray_getArrayLength(KConstRef thiz) { @@ -249,7 +249,7 @@ void Kotlin_LongArray_set(KRef thiz, KInt index, KLong value) { *PrimitiveArrayAddressOfElementAt(array, index) = value; } -KRef Kotlin_LongArray_clone(KConstRef thiz) { +OBJ_GETTER(Kotlin_LongArray_clone, KConstRef thiz) { const ArrayHeader* array = thiz->array(); ArrayHeader* result = ArrayContainer( theLongArrayTypeInfo, array->count_).GetPlace(); @@ -257,7 +257,7 @@ KRef Kotlin_LongArray_clone(KConstRef thiz) { PrimitiveArrayAddressOfElementAt(result, 0), PrimitiveArrayAddressOfElementAt(array, 0), ArrayDataSizeBytes(array)); - return result->obj(); + RETURN_OBJ(result->obj()); } KInt Kotlin_LongArray_getArrayLength(KConstRef thiz) { @@ -281,7 +281,7 @@ void Kotlin_FloatArray_set(KRef thiz, KInt index, KFloat value) { *PrimitiveArrayAddressOfElementAt(array, index) = value; } -KRef Kotlin_FloatArray_clone(KConstRef thiz) { +OBJ_GETTER(Kotlin_FloatArray_clone, KConstRef thiz) { const ArrayHeader* array = thiz->array(); ArrayHeader* result = ArrayContainer( theFloatArrayTypeInfo, array->count_).GetPlace(); @@ -289,7 +289,7 @@ KRef Kotlin_FloatArray_clone(KConstRef thiz) { PrimitiveArrayAddressOfElementAt(result, 0), PrimitiveArrayAddressOfElementAt(array, 0), ArrayDataSizeBytes(array)); - return result->obj(); + RETURN_OBJ(result->obj()); } KInt Kotlin_FloatArray_getArrayLength(KConstRef thiz) { @@ -313,7 +313,7 @@ void Kotlin_DoubleArray_set(KRef thiz, KInt index, KDouble value) { *PrimitiveArrayAddressOfElementAt(array, index) = value; } -KRef Kotlin_DoubleArray_clone(KConstRef thiz) { +OBJ_GETTER(Kotlin_DoubleArray_clone, KConstRef thiz) { const ArrayHeader* array = thiz->array(); ArrayHeader* result = ArrayContainer( theDoubleArrayTypeInfo, array->count_).GetPlace(); @@ -321,7 +321,7 @@ KRef Kotlin_DoubleArray_clone(KConstRef thiz) { PrimitiveArrayAddressOfElementAt(result, 0), PrimitiveArrayAddressOfElementAt(array, 0), ArrayDataSizeBytes(array)); - return result->obj(); + RETURN_OBJ(result->obj()); } KInt Kotlin_DoubleArray_getArrayLength(KConstRef thiz) { @@ -345,7 +345,7 @@ void Kotlin_BooleanArray_set(KRef thiz, KInt index, KBoolean value) { *PrimitiveArrayAddressOfElementAt(array, index) = value; } -KRef Kotlin_BooleanArray_clone(KConstRef thiz) { +OBJ_GETTER(Kotlin_BooleanArray_clone, KConstRef thiz) { const ArrayHeader* array = thiz->array(); ArrayHeader* result = ArrayContainer( theBooleanArrayTypeInfo, array->count_).GetPlace(); @@ -353,7 +353,7 @@ KRef Kotlin_BooleanArray_clone(KConstRef thiz) { PrimitiveArrayAddressOfElementAt(result, 0), PrimitiveArrayAddressOfElementAt(array, 0), ArrayDataSizeBytes(array)); - return result->obj(); + RETURN_OBJ(result->obj()); } KInt Kotlin_BooleanArray_getArrayLength(KConstRef thiz) { diff --git a/runtime/src/main/cpp/Exceptions.cpp b/runtime/src/main/cpp/Exceptions.cpp index d404be7161d..6b704d67362 100644 --- a/runtime/src/main/cpp/Exceptions.cpp +++ b/runtime/src/main/cpp/Exceptions.cpp @@ -4,6 +4,7 @@ #include "Assert.h" #include "Exceptions.h" +#include "Memory.h" #include "Natives.h" #include "Types.h" @@ -34,18 +35,13 @@ class AutoFree { } }; -// TODO: this method ignores the encoding. -KString CreateKotlinStringFromCString(const char* str) { - return AllocStringInstance(SCOPE_GLOBAL, str, strlen(str))->array(); -} - #ifdef __cplusplus extern "C" { #endif // TODO: this implementation is just a hack, e.g. the result is inexact; // however it is better to have an inexact stacktrace than not to have any. -KRef GetCurrentStackTrace() { +OBJ_GETTER0(GetCurrentStackTrace) { const int maxSize = 32; void* buffer[maxSize]; @@ -54,20 +50,21 @@ KRef GetCurrentStackTrace() { RuntimeAssert(symbols != nullptr, "Not enough memory to retrieve the stacktrace"); AutoFree autoFree(symbols); - KRef result = AllocArrayInstance(theArrayTypeInfo, SCOPE_GLOBAL, size); + AllocArrayInstance(theArrayTypeInfo, SCOPE_GLOBAL, size, OBJ_RESULT); - for (int i = 0; i < size; ++i) { - KString symbol = CreateKotlinStringFromCString(symbols[i]); - Kotlin_Array_set(result, i, symbol->obj()); + ArrayHeader* array = (*OBJ_RESULT)->array(); + for (int index = 0; index < size; ++index) { + AllocStringInstance( + SCOPE_GLOBAL, symbols[index], strlen(symbols[index]), + ArrayAddressOfElementAt(array, index)); } - return result; + RETURN_OBJ_RESULT(); } void ThrowException(KRef exception) { RuntimeAssert(exception != nullptr && IsInstance(exception, theThrowableTypeInfo), "Throwing something non-throwable"); - throw KotlinException(exception); } diff --git a/runtime/src/main/cpp/Exceptions.h b/runtime/src/main/cpp/Exceptions.h index 4229eae2781..ce6b2b18fa5 100644 --- a/runtime/src/main/cpp/Exceptions.h +++ b/runtime/src/main/cpp/Exceptions.h @@ -8,7 +8,7 @@ extern "C" { #endif // Returns current stacktrace as Array. -KRef GetCurrentStackTrace(); +OBJ_GETTER0(GetCurrentStackTrace); // Throws arbitrary exception. void ThrowException(KRef exception); diff --git a/runtime/src/main/cpp/Memory.cpp b/runtime/src/main/cpp/Memory.cpp index eb997826059..c25cbe44220 100644 --- a/runtime/src/main/cpp/Memory.cpp +++ b/runtime/src/main/cpp/Memory.cpp @@ -88,30 +88,30 @@ void InitMemory() { } // Now we ignore all placement hints and always allocate heap space for new object. -ObjHeader* AllocInstance(const TypeInfo* type_info, PlacementHint hint) { +OBJ_GETTER(AllocInstance, const TypeInfo* type_info, PlacementHint hint) { RuntimeAssert(type_info->instanceSize_ >= 0, "must be an object"); - return ObjectContainer(type_info).GetPlace(); + RETURN_OBJ(ObjectContainer(type_info).GetPlace()); } -ObjHeader* AllocArrayInstance( - const TypeInfo* type_info, PlacementHint hint, uint32_t elements) { +OBJ_GETTER(AllocArrayInstance, + const TypeInfo* type_info, PlacementHint hint, uint32_t elements) { RuntimeAssert(type_info->instanceSize_ < 0, "must be an array"); - return ArrayContainer(type_info, elements).GetPlace()->obj(); + RETURN_OBJ(ArrayContainer(type_info, elements).GetPlace()->obj()); } -ObjHeader* AllocStringInstance( - PlacementHint hint, const char* data, uint32_t length) { - ArrayHeader* result = ArrayContainer(theStringTypeInfo, length).GetPlace(); +OBJ_GETTER(AllocStringInstance, + PlacementHint hint, const char* data, uint32_t length) { + ArrayHeader* array = ArrayContainer(theStringTypeInfo, length).GetPlace(); memcpy( - ByteArrayAddressOfElementAt(result, 0), + ByteArrayAddressOfElementAt(array, 0), data, length); - return result->obj(); + RETURN_OBJ(array->obj()); } -ObjHeader* InitInstance( +OBJ_GETTER(InitInstance, ObjHeader** location, const TypeInfo* type_info, PlacementHint hint, - ObjHeader* (*ctor)(ObjHeader*)) { + void (*ctor)(ObjHeader*)) { ObjHeader* sentinel = reinterpret_cast(1); ObjHeader* value; // Wait until other initializers. @@ -122,21 +122,34 @@ ObjHeader* InitInstance( if (value != nullptr) { // OK'ish, inited by someone else. - return value; + RETURN_OBJ(value); } - ObjHeader* instance = AllocInstance(type_info, hint); + AllocInstance(type_info, hint, OBJ_RESULT); try { - ctor(instance); - __sync_val_compare_and_swap(location, sentinel, instance); - return instance; + ctor(*OBJ_RESULT); + bool ok = __sync_bool_compare_and_swap(location, sentinel, *OBJ_RESULT); + RuntimeAssert(ok, "CAS must succeed"); + RETURN_OBJ_RESULT(); } catch (...) { - Release(instance->container()); __sync_val_compare_and_swap(location, sentinel, nullptr); - return nullptr; + RETURN_OBJ(nullptr); } } +// Just stubs. +void SetLocalRef(ObjHeader** location, const ObjHeader* object) { + *const_cast(location) = object; +} + +void UpdateLocalRef(ObjHeader** location, const ObjHeader* object) { + *const_cast(location) = object; +} + +void UpdateGlobalRef(ObjHeader** location, const ObjHeader* object) { + *const_cast(location) = object; +} + #ifdef __cplusplus } #endif diff --git a/runtime/src/main/cpp/Memory.h b/runtime/src/main/cpp/Memory.h index 759c4d42189..7fdad06ff5a 100644 --- a/runtime/src/main/cpp/Memory.h +++ b/runtime/src/main/cpp/Memory.h @@ -282,18 +282,55 @@ class ArenaContainer : public Container { extern "C" { #endif +#define OBJ_RESULT __result__ +#define OBJ_GETTER0(name) ObjHeader* name(ObjHeader** OBJ_RESULT) +#define OBJ_GETTER(name, ...) ObjHeader* name(__VA_ARGS__, ObjHeader** OBJ_RESULT) +#define RETURN_OBJ(value) UpdateLocalRef(OBJ_RESULT, value); return value; +#define RETURN_OBJ_RESULT() return *OBJ_RESULT; +#define RETURN_RESULT_OF0(name) name(OBJ_RESULT); return *OBJ_RESULT; +#define RETURN_RESULT_OF(name, ...) name(__VA_ARGS__, OBJ_RESULT); return *OBJ_RESULT; + void InitMemory(); -ObjHeader* AllocInstance(const TypeInfo* type_info, PlacementHint hint); -ObjHeader* AllocArrayInstance( - const TypeInfo* type_info, PlacementHint hint, uint32_t elements); -ObjHeader* AllocStringInstance(PlacementHint hint, - const char* data, uint32_t length); -ObjHeader* InitInstance( - ObjHeader** location, const TypeInfo* type_info, PlacementHint hint, - ObjHeader* (*ctor)(ObjHeader*)); +OBJ_GETTER(AllocInstance, const TypeInfo* type_info, PlacementHint hint); +OBJ_GETTER(AllocArrayInstance, + const TypeInfo* type_info, PlacementHint hint, uint32_t elements); +OBJ_GETTER(AllocStringInstance, + PlacementHint hint, const char* data, uint32_t length); +OBJ_GETTER(InitInstance, + ObjHeader** location, const TypeInfo* type_info, PlacementHint hint, + void (*ctor)(ObjHeader*)); + +// Sets locally visible location. +void SetLocalRef(ObjHeader** location, const ObjHeader* object); +// Sets potentially globally visible location. +void SetGlobalRef(ObjHeader** location, const ObjHeader* object); +// Update locally visible location. +void UpdateLocalRef(ObjHeader** location, const ObjHeader* object); +// Update potentially globally visible location. +void UpdateGlobalRef(ObjHeader** location, const ObjHeader* object); #ifdef __cplusplus } #endif +// Class holding reference to an object, holding object during C++ scope. +class ObjHolder { + public: + ObjHolder() : obj_(nullptr) {} + + explicit ObjHolder(const ObjHeader* obj) { + ::SetLocalRef(&obj_, obj); + } + ~ObjHolder() { + ::UpdateLocalRef(&obj_, nullptr); + } + + ObjHeader* obj() { return obj_; } + const ObjHeader* obj() const { return obj_; } + ObjHeader** slot() { return &obj_; } + + private: + ObjHeader* obj_; +}; + #endif // RUNTIME_MEMORY_H diff --git a/runtime/src/main/cpp/Natives.cpp b/runtime/src/main/cpp/Natives.cpp index 7b9d717c7a1..3641451cd65 100644 --- a/runtime/src/main/cpp/Natives.cpp +++ b/runtime/src/main/cpp/Natives.cpp @@ -22,7 +22,8 @@ KInt Kotlin_Any_hashCode(KConstRef thiz) { return reinterpret_cast(thiz); } -KString Kotlin_Any_toString(KConstRef thiz) { +OBJ_GETTER(Kotlin_Any_toString, KConstRef thiz) { + // TODO: make it more sensible, such as address and type info. return nullptr; } @@ -44,7 +45,7 @@ void Kotlin_io_Console_println0() { write(STDOUT_FILENO, "\n", 1); } -KString Kotlin_io_Console_readLine() { +OBJ_GETTER0(Kotlin_io_Console_readLine) { char data[2048]; if (!fgets(data, sizeof(data) - 1, stdin)) { return nullptr; @@ -54,7 +55,7 @@ KString Kotlin_io_Console_readLine() { memcpy( ByteArrayAddressOfElementAt(result, 0), data, length); - return result; + RETURN_OBJ(result->obj()); } // String.kt @@ -76,7 +77,7 @@ KInt Kotlin_String_getStringLength(KString thiz) { return thiz->count_; } -KString Kotlin_String_fromUtf8Array(KConstRef thiz, KInt start, KInt size) { +OBJ_GETTER(Kotlin_String_fromUtf8Array, KConstRef thiz, KInt start, KInt size) { const ArrayHeader* array = thiz->array(); RuntimeAssert(array->type_info() == theByteArrayTypeInfo, "Must use a byte array"); if (start < 0 || size < 0 || start + size > array->count_) { @@ -84,7 +85,7 @@ KString Kotlin_String_fromUtf8Array(KConstRef thiz, KInt start, KInt size) { } if (size == 0) { - return TheEmptyString(); + RETURN_RESULT_OF0(TheEmptyString); } // TODO: support full UTF-8. @@ -93,10 +94,10 @@ KString Kotlin_String_fromUtf8Array(KConstRef thiz, KInt start, KInt size) { ByteArrayAddressOfElementAt(result, 0), ByteArrayAddressOfElementAt(array, start), size); - return result; + RETURN_OBJ(result->obj()); } -KString Kotlin_String_fromCharArray(KConstRef thiz, KInt start, KInt size) { +OBJ_GETTER(Kotlin_String_fromCharArray, KConstRef thiz, KInt start, KInt size) { const ArrayHeader* array = thiz->array(); RuntimeAssert(array->type_info() == theCharArrayTypeInfo, "Must use a byte array"); if (start < 0 || size < 0 || start + size > array->count_) { @@ -104,7 +105,7 @@ KString Kotlin_String_fromCharArray(KConstRef thiz, KInt start, KInt size) { } if (size == 0) { - return TheEmptyString(); + RETURN_RESULT_OF0(TheEmptyString); } // TODO: support full UTF-8. @@ -113,10 +114,10 @@ KString Kotlin_String_fromCharArray(KConstRef thiz, KInt start, KInt size) { *ByteArrayAddressOfElementAt(result, index) = *PrimitiveArrayAddressOfElementAt(array, start + index); } - return result; + RETURN_OBJ(result->obj()); } -KRef Kotlin_String_toCharArray(KString string) { +OBJ_GETTER(Kotlin_String_toCharArray, KString string) { // TODO: support full UTF-8. ArrayHeader* result = ArrayContainer( theCharArrayTypeInfo, string->count_).GetPlace(); @@ -124,11 +125,11 @@ KRef Kotlin_String_toCharArray(KString string) { *PrimitiveArrayAddressOfElementAt(result, index) = *ByteArrayAddressOfElementAt(string, index); } - return result->obj(); + RETURN_OBJ(result->obj()); } -KString Kotlin_String_plusImpl(KString thiz, KString other) { +OBJ_GETTER(Kotlin_String_plusImpl, KString thiz, KString other) { // TODO: support UTF-8 RuntimeAssert(thiz != nullptr, "this cannot be null"); RuntimeAssert(other != nullptr, "other cannot be null"); @@ -145,7 +146,7 @@ KString Kotlin_String_plusImpl(KString thiz, KString other) { ByteArrayAddressOfElementAt(result, thiz->count_), ByteArrayAddressOfElementAt(other, 0), other->count_); - return result; + RETURN_OBJ(result->obj()); } KBoolean Kotlin_String_equals(KString thiz, KConstRef other) { @@ -165,13 +166,13 @@ KInt Kotlin_String_hashCode(KString thiz) { return CityHash64(ByteArrayAddressOfElementAt(thiz, 0), thiz->count_); } -KString Kotlin_String_subSequence(KString thiz, KInt startIndex, KInt endIndex) { +OBJ_GETTER(Kotlin_String_subSequence, KString thiz, KInt startIndex, KInt endIndex) { if (startIndex < 0 || endIndex >= thiz->count_ || startIndex > endIndex) { // TODO: is it correct exception? ThrowArrayIndexOutOfBoundsException(); } if (startIndex == endIndex) { - return TheEmptyString(); + RETURN_RESULT_OF0(TheEmptyString); } // TODO: support UTF-8. KInt length = endIndex - startIndex; @@ -179,16 +180,16 @@ KString Kotlin_String_subSequence(KString thiz, KInt startIndex, KInt endIndex) memcpy(ByteArrayAddressOfElementAt(result, 0), ByteArrayAddressOfElementAt(thiz, startIndex), length); - return result; + RETURN_OBJ(result->obj()); } -KConstRef Kotlin_getCurrentStackTrace() { - return GetCurrentStackTrace(); +OBJ_GETTER0(Kotlin_getCurrentStackTrace) { + RETURN_RESULT_OF0(GetCurrentStackTrace); } // TODO: consider handling it with compiler magic instead. -KRef Kotlin_konan_internal_undefined() { - return nullptr; +OBJ_GETTER0(Kotlin_konan_internal_undefined) { + RETURN_OBJ(nullptr); } } // extern "C" diff --git a/runtime/src/main/cpp/Natives.h b/runtime/src/main/cpp/Natives.h index 9a56e14d970..17b57d0918d 100644 --- a/runtime/src/main/cpp/Natives.h +++ b/runtime/src/main/cpp/Natives.h @@ -37,8 +37,8 @@ inline const T* PrimitiveArrayAddressOfElementAt( return reinterpret_cast(obj + 1) + index; } -inline KConstRef* ArrayAddressOfElementAt(ArrayHeader* obj, KInt index) { - return reinterpret_cast(obj + 1) + index; +inline KRef* ArrayAddressOfElementAt(ArrayHeader* obj, KInt index) { + return reinterpret_cast(obj + 1) + index; } inline const KRef* ArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) { @@ -49,31 +49,32 @@ inline const KRef* ArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) { extern "C" { #endif -KString TheEmptyString(); +// RuntimeUtils.kt. +OBJ_GETTER0(TheEmptyString); // Any.kt KBoolean Kotlin_Any_equals(KConstRef thiz, KConstRef other); KInt Kotlin_Any_hashCode(KConstRef thiz); -KString Kotlin_Any_toString(KConstRef thiz); +OBJ_GETTER(Kotlin_Any_toString, KConstRef thiz); // Arrays.kt // TODO: those must be compiler intrinsics afterwards. -KRef Kotlin_Array_clone(KConstRef thiz); -KRef Kotlin_Array_get(KConstRef thiz, KInt index); +OBJ_GETTER(Kotlin_Array_clone, KConstRef thiz); +OBJ_GETTER(Kotlin_Array_get, KConstRef thiz, KInt index); void Kotlin_Array_set(KRef thiz, KInt index, KConstRef value); KInt Kotlin_Array_getArrayLength(KConstRef thiz); -KRef Kotlin_ByteArray_clone(KConstRef thiz); +OBJ_GETTER(Kotlin_ByteArray_clone, KConstRef thiz); KByte Kotlin_ByteArray_get(KConstRef thiz, KInt index); void Kotlin_ByteArray_set(KRef thiz, KInt index, KByte value); KInt Kotlin_ByteArray_getArrayLength(KConstRef thiz); -KRef Kotlin_CharArray_clone(KConstRef thiz); +OBJ_GETTER(Kotlin_CharArray_clone, KConstRef thiz); KChar Kotlin_CharArray_get(KConstRef thiz, KInt index); void Kotlin_CharArray_set(KRef thiz, KInt index, KChar value); KInt Kotlin_CharArray_getArrayLength(KConstRef thiz); -KRef Kotlin_IntArray_clone(KConstRef thiz); +OBJ_GETTER(Kotlin_IntArray_clone, KConstRef thiz); KInt Kotlin_IntArray_get(KConstRef thiz, KInt index); void Kotlin_IntArray_set(KRef thiz, KInt index, KInt value); KInt Kotlin_IntArray_getArrayLength(KConstRef thiz); @@ -82,25 +83,25 @@ KInt Kotlin_IntArray_getArrayLength(KConstRef thiz); void Kotlin_io_Console_print(KString message); void Kotlin_io_Console_println(KString message); void Kotlin_io_Console_println0(); -KString Kotlin_io_Console_readLine(); +OBJ_GETTER0(Kotlin_io_Console_readLine); // Primitives.kt. -KString Kotlin_Int_toString(KInt value); +OBJ_GETTER(Kotlin_Int_toString, KInt value); // String.kt KInt Kotlin_String_hashCode(KString thiz); KBoolean Kotlin_String_equals(KString thiz, KConstRef other); KInt Kotlin_String_compareTo(KString thiz, KString other); KChar Kotlin_String_get(KString thiz, KInt index); -KString Kotlin_String_fromUtf8Array(KConstRef array, KInt start, KInt size); -KString Kotlin_String_fromCharArray(KConstRef array, KInt start, KInt size); -KString Kotlin_String_plusImpl(KString thiz, KString other); +OBJ_GETTER(Kotlin_String_fromUtf8Array, KConstRef array, KInt start, KInt size); +OBJ_GETTER(Kotlin_String_fromCharArray, KConstRef array, KInt start, KInt size); +OBJ_GETTER(Kotlin_String_plusImpl, KString thiz, KString other); KInt Kotlin_String_getStringLength(KString thiz); -KString Kotlin_String_subSequence(KString thiz, KInt startIndex, KInt endIndex); +OBJ_GETTER(Kotlin_String_subSequence, KString thiz, KInt startIndex, KInt endIndex); -KConstRef Kotlin_getCurrentStackTrace(); +OBJ_GETTER0(Kotlin_getCurrentStackTrace); -KRef Kotlin_konan_internal_undefined(); +OBJ_GETTER0(Kotlin_konan_internal_undefined); #ifdef __cplusplus } diff --git a/runtime/src/main/cpp/ToString.cpp b/runtime/src/main/cpp/ToString.cpp index c2d6a30ad24..ab42153d84a 100644 --- a/runtime/src/main/cpp/ToString.cpp +++ b/runtime/src/main/cpp/ToString.cpp @@ -9,7 +9,7 @@ namespace { -KString makeString(const char* cstring) { +OBJ_GETTER(makeString, const char* cstring) { uint32_t length = strlen(cstring); ArrayHeader* result = ArrayContainer( theStringTypeInfo, length).GetPlace(); @@ -17,59 +17,59 @@ KString makeString(const char* cstring) { ByteArrayAddressOfElementAt(result, 0), cstring, length); - return result; + RETURN_OBJ(result->obj()); } } // namespace extern "C" { -KString Kotlin_Byte_toString(KByte value) { +OBJ_GETTER(Kotlin_Byte_toString, KByte value) { char cstring[8]; snprintf(cstring, sizeof(cstring), "%d", value); - return makeString(cstring); + RETURN_RESULT_OF(makeString, cstring); } -KString Kotlin_Char_toString(KChar value) { +OBJ_GETTER(Kotlin_Char_toString, KChar value) { char cstring[5]; // TODO: support UTF-8. snprintf(cstring, sizeof(cstring), "%c", value); - return makeString(cstring); + RETURN_RESULT_OF(makeString, cstring); } -KString Kotlin_Short_toString(KShort value) { +OBJ_GETTER(Kotlin_Short_toString, KShort value) { char cstring[8]; snprintf(cstring, sizeof(cstring), "%d", value); - return makeString(cstring); + RETURN_RESULT_OF(makeString, cstring); } -KString Kotlin_Int_toString(KInt value) { +OBJ_GETTER(Kotlin_Int_toString, KInt value) { char cstring[16]; snprintf(cstring, sizeof(cstring), "%d", value); - return makeString(cstring); + RETURN_RESULT_OF(makeString, cstring); } -KString Kotlin_Long_toString(KLong value) { +OBJ_GETTER(Kotlin_Long_toString, KLong value) { char cstring[32]; snprintf(cstring, sizeof(cstring), "%lld", static_cast(value)); - return makeString(cstring); + RETURN_RESULT_OF(makeString, cstring); } // TODO: use David Gay's dtoa() here instead. It's *very* big and ugly. -KString Kotlin_Float_toString(KFloat value) { +OBJ_GETTER(Kotlin_Float_toString, KFloat value) { char cstring[32]; snprintf(cstring, sizeof(cstring), "%G", value); - return makeString(cstring); + RETURN_RESULT_OF(makeString, cstring); } -KString Kotlin_Double_toString(KDouble value) { +OBJ_GETTER(Kotlin_Double_toString, KDouble value) { char cstring[32]; snprintf(cstring, sizeof(cstring), "%G", value); - return makeString(cstring); + RETURN_RESULT_OF(makeString, cstring); } -KString Kotlin_Boolean_toString(KBoolean value) { - return makeString(value ? "true" : "false"); +OBJ_GETTER(Kotlin_Boolean_toString, KBoolean value) { + RETURN_RESULT_OF(makeString, value ? "true" : "false"); } } // extern "C"