diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt index f7202903b62..4f897356a01 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt @@ -59,6 +59,7 @@ interface IrDeclarationOrigin { object IR_BUILTINS_STUB : IrDeclarationOriginImpl("IR_BUILTINS_STUB") object BRIDGE : IrDeclarationOriginImpl("BRIDGE", isSynthetic = true) object BRIDGE_SPECIAL : IrDeclarationOriginImpl("BRIDGE_SPECIAL") + object GENERATED_SETTER_GETTER : IrDeclarationOriginImpl("GENERATED_SETTER_GETTER", isSynthetic = true) object FIELD_FOR_ENUM_ENTRY : IrDeclarationOriginImpl("FIELD_FOR_ENUM_ENTRY") object SYNTHETIC_HELPER_FOR_ENUM_VALUES : IrDeclarationOriginImpl("SYNTHETIC_HELPER_FOR_ENUM_VALUES", isSynthetic = true) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt index 241e25b5d7e..5127a10132a 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt @@ -85,6 +85,9 @@ fun IrSimpleFunction.overrides(other: IrSimpleFunction): Boolean { private val IrConstructorCall.annotationClass get() = this.symbol.owner.constructedClass +fun IrConstructorCall.isAnnotationWithEqualFqName(fqName: FqName): Boolean = + annotationClass.hasEqualFqName(fqName) + val IrClass.packageFqName: FqName? get() = symbol.signature?.packageFqName() ?: parent.getPackageFragment()?.fqName diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt index be80d07dd11..51dd4bbb567 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLoweringPhases.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.lower.loops.ForLoopsLowering import org.jetbrains.kotlin.backend.common.lower.optimizations.FoldConstantLowering import org.jetbrains.kotlin.backend.common.lower.optimizations.PropertyAccessorInlineLowering import org.jetbrains.kotlin.backend.common.phaser.* +import org.jetbrains.kotlin.backend.konan.ir.FunctionsWithoutBCGenerator import org.jetbrains.kotlin.backend.konan.lower.* import org.jetbrains.kotlin.backend.konan.lower.FinallyBlocksLowering import org.jetbrains.kotlin.backend.konan.lower.InitializersLowering @@ -331,11 +332,19 @@ internal val interopPhase = makeKonanFileLoweringPhase( prerequisite = setOf(inlinePhase, localFunctionsPhase, functionReferencePhase) ) +internal val functionsWithoutBC = makeKonanModuleOpPhase( + name = "FunctionsWithoutBCGenerator", + description = "Functions without bounds check generation", + op = { context, _ -> + FunctionsWithoutBCGenerator(context).generate() + } +) + internal val varargPhase = makeKonanFileLoweringPhase( ::VarargInjectionLowering, name = "Vararg", description = "Vararg lowering", - prerequisite = setOf(functionReferencePhase, defaultParameterExtentPhase, interopPhase) + prerequisite = setOf(functionReferencePhase, defaultParameterExtentPhase, interopPhase, functionsWithoutBC) ) internal val compileTimeEvaluatePhase = makeKonanFileLoweringPhase( diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt index e5e413bd01c..55970dd943e 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt @@ -390,6 +390,7 @@ private val backendCodegen = namedUnitPhase( name = "Backend codegen", description = "Backend code generation", lower = takeFromContext { it.irModule!! } then + functionsWithoutBC then allLoweringsPhase then // Lower current module first. dependenciesLowerPhase then // Then lower all libraries in topological order. // With that we guarantee that inline functions are unlowered while being inlined. diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/FunctionsWithoutBCGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/FunctionsWithoutBCGenerator.kt new file mode 100644 index 00000000000..841c21c3246 --- /dev/null +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/FunctionsWithoutBCGenerator.kt @@ -0,0 +1,78 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the LICENSE file. + */ + +package org.jetbrains.kotlin.backend.konan.ir + +import org.jetbrains.kotlin.backend.common.ir.copyTo +import org.jetbrains.kotlin.backend.common.ir.createDispatchReceiverParameter +import org.jetbrains.kotlin.backend.konan.KonanBackendContext +import org.jetbrains.kotlin.backend.konan.KonanFqNames +import org.jetbrains.kotlin.backend.konan.descriptors.getAnnotationStringValue +import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET +import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.declarations.addMember +import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl +import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols +import org.jetbrains.kotlin.ir.util.functions +import org.jetbrains.kotlin.ir.util.isAnnotationWithEqualFqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.util.OperatorNameConventions + +// Generate additional functions for array set and get operators without bounds checking. +internal class FunctionsWithoutBCGenerator(val context: KonanBackendContext) { + private val symbols = context.ir.symbols + + private fun generateFunction(baseFunction: IrSimpleFunction, functionName: Name) = + context.irFactory.createFunction( + baseFunction.startOffset, baseFunction.endOffset, + IrDeclarationOrigin.GENERATED_SETTER_GETTER, + IrSimpleFunctionSymbolImpl(), + functionName, + DescriptorVisibilities.PUBLIC, + Modality.FINAL, + baseFunction.returnType, + isInline = baseFunction.isInline, + isExternal = baseFunction.isExternal, + isTailrec = baseFunction.isTailrec, + isSuspend = baseFunction.isSuspend, + isExpect = baseFunction.isExpect, + isFakeOverride = baseFunction.isFakeOverride, + isOperator = baseFunction.isOperator, + isInfix = baseFunction.isInfix + ).also { function -> + function.parent = baseFunction.parent + function.createDispatchReceiverParameter() + function.valueParameters = baseFunction.valueParameters.map { it.copyTo(function) } + // Copy annotations. + val setWithoutBEAnnotations = baseFunction.annotations.map { annotation -> + annotation.deepCopyWithSymbols().also { copy -> + if (copy.isAnnotationWithEqualFqName(KonanFqNames.gcUnsafeCall)) { + val value = "${annotation.getAnnotationStringValue("callee")}_without_BC" + copy.putValueArgument(0, + IrConstImpl.string(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.stringType, value)) + } + } + } + function.annotations = setWithoutBEAnnotations + } + + + fun generate() { + val arraysClasses = symbols.primitiveArrays.values + symbols.array + arraysClasses.forEach { classSymbol -> + val setFunction = classSymbol.owner.functions.single { it.name == OperatorNameConventions.SET } + classSymbol.owner.addMember(generateFunction(setFunction, KonanNameConventions.setWithoutBC)) + + val getFunction = classSymbol.owner.functions.single { it.descriptor.name == OperatorNameConventions.GET } + classSymbol.owner.addMember(generateFunction(getFunction, KonanNameConventions.getWithoutBC)) + } + } +} \ No newline at end of file diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt index 13734173821..c1978409157 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt @@ -39,6 +39,11 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.Variance import kotlin.properties.Delegates +object KonanNameConventions { + val setWithoutBC = Name.special("") + val getWithoutBC = Name.special("") +} + // This is what Context collects about IR. internal class KonanIr(context: Context, irModule: IrModuleFragment): Ir(context, irModule) { override var symbols: KonanSymbols by Delegates.notNull() diff --git a/kotlin-native/runtime/src/main/cpp/Arrays.cpp b/kotlin-native/runtime/src/main/cpp/Arrays.cpp index 5c7192ae0b4..159a86f370a 100644 --- a/kotlin-native/runtime/src/main/cpp/Arrays.cpp +++ b/kotlin-native/runtime/src/main/cpp/Arrays.cpp @@ -71,21 +71,57 @@ inline void copyImpl(KConstRef thiz, KInt fromIndex, } -template +template inline void PrimitiveArraySet(KRef thiz, KInt index, T value) { ArrayHeader* array = thiz->array(); - boundsCheck(array, index); + if (BoundsCheck) + boundsCheck(array, index); mutabilityCheck(thiz); *PrimitiveArrayAddressOfElementAt(array, index) = value; } -template +template inline T PrimitiveArrayGet(KConstRef thiz, KInt index) { const ArrayHeader* array = thiz->array(); - boundsCheck(array, index); + if (BoundsCheck) + boundsCheck(array, index); return *PrimitiveArrayAddressOfElementAt(array, index); } +template +ALWAYS_INLINE const KRef* Kotlin_Array_get_value(KConstRef thiz, KInt index) { + const ArrayHeader* array = thiz->array(); + if (BoundsCheck) + boundsCheck(array, index); + return ArrayAddressOfElementAt(array, index); +} + +template +ALWAYS_INLINE void Kotlin_Array_set_value(KRef thiz, KInt index, KConstRef value) { + ArrayHeader* array = thiz->array(); + if (BoundsCheck) + boundsCheck(array, index); + mutabilityCheck(thiz); + UpdateHeapRef(ArrayAddressOfElementAt(array, index), value); +} + +template +ALWAYS_INLINE KByte Kotlin_ByteArray_get_value(KConstRef thiz, KInt index) { + const ArrayHeader* array = thiz->array(); + if (BoundsCheck) + boundsCheck(array, index); + return *ByteArrayAddressOfElementAt(array, index); +} + +template +ALWAYS_INLINE void Kotlin_ByteArray_set_value(KRef thiz, KInt index, KByte value) { + ArrayHeader* array = thiz->array(); + if (BoundsCheck) + boundsCheck(array, index); + mutabilityCheck(thiz); + *ByteArrayAddressOfElementAt(array, index) = value; +} + } // namespace extern "C" { @@ -97,16 +133,19 @@ extern const ObjHeader theEmptyArray; // Array.kt OBJ_GETTER(Kotlin_Array_get, KConstRef thiz, KInt index) { - const ArrayHeader* array = thiz->array(); - boundsCheck(array, index); - RETURN_OBJ(*ArrayAddressOfElementAt(array, index)); + RETURN_OBJ(*Kotlin_Array_get_value(thiz, index)); +} + +OBJ_GETTER(Kotlin_Array_get_without_BC, KConstRef thiz, KInt index){ + RETURN_OBJ(*Kotlin_Array_get_value(thiz, index)); } void Kotlin_Array_set(KRef thiz, KInt index, KConstRef value) { - ArrayHeader* array = thiz->array(); - boundsCheck(array, index); - mutabilityCheck(thiz); - UpdateHeapRef(ArrayAddressOfElementAt(array, index), value); + Kotlin_Array_set_value(thiz, index, value); +} + +void Kotlin_Array_set_without_BC(KRef thiz, KInt index, KConstRef value) { + Kotlin_Array_set_value(thiz, index, value); } KInt Kotlin_Array_getArrayLength(KConstRef thiz) { @@ -157,16 +196,19 @@ OBJ_GETTER0(Kotlin_emptyArray) { } KByte Kotlin_ByteArray_get(KConstRef thiz, KInt index) { - const ArrayHeader* array = thiz->array(); - boundsCheck(array, index); - return *ByteArrayAddressOfElementAt(array, index); + return Kotlin_ByteArray_get_value(thiz, index); +} + +KByte Kotlin_ByteArray_get_without_BC(KConstRef thiz, KInt index) { + return Kotlin_ByteArray_get_value(thiz, index); } void Kotlin_ByteArray_set(KRef thiz, KInt index, KByte value) { - ArrayHeader* array = thiz->array(); - boundsCheck(array, index); - mutabilityCheck(thiz); - *ByteArrayAddressOfElementAt(array, index) = value; + Kotlin_ByteArray_set_value(thiz, index, value); +} + +void Kotlin_ByteArray_set_without_BC(KRef thiz, KInt index, KByte value) { + Kotlin_ByteArray_set_value(thiz, index, value); } KInt Kotlin_ByteArray_getArrayLength(KConstRef thiz) { @@ -447,10 +489,18 @@ KChar Kotlin_CharArray_get(KConstRef thiz, KInt index) { return PrimitiveArrayGet(thiz, index); } +KChar Kotlin_CharArray_get_without_BC(KConstRef thiz, KInt index) { + return PrimitiveArrayGet(thiz, index); +} + void Kotlin_CharArray_set(KRef thiz, KInt index, KChar value) { PrimitiveArraySet(thiz, index, value); } +void Kotlin_CharArray_set_without_BC(KRef thiz, KInt index, KChar value) { + PrimitiveArraySet(thiz, index, value); +} + OBJ_GETTER(Kotlin_CharArray_copyOf, KConstRef thiz, KInt newSize) { const ArrayHeader* array = thiz->array(); if (newSize < 0) { @@ -474,10 +524,18 @@ KShort Kotlin_ShortArray_get(KConstRef thiz, KInt index) { return PrimitiveArrayGet(thiz, index); } +KShort Kotlin_ShortArray_get_without_BC(KConstRef thiz, KInt index) { + return PrimitiveArrayGet(thiz, index); +} + void Kotlin_ShortArray_set(KRef thiz, KInt index, KShort value) { PrimitiveArraySet(thiz, index, value); } +void Kotlin_ShortArray_set_without_BC(KRef thiz, KInt index, KShort value) { + PrimitiveArraySet(thiz, index, value); +} + KInt Kotlin_ShortArray_getArrayLength(KConstRef thiz) { const ArrayHeader* array = thiz->array(); return array->count_; @@ -487,10 +545,18 @@ KInt Kotlin_IntArray_get(KConstRef thiz, KInt index) { return PrimitiveArrayGet(thiz, index); } +KInt Kotlin_IntArray_get_without_BC(KConstRef thiz, KInt index) { + return PrimitiveArrayGet(thiz, index); +} + void Kotlin_IntArray_set(KRef thiz, KInt index, KInt value) { PrimitiveArraySet(thiz, index, value); } +void Kotlin_IntArray_set_without_BC(KRef thiz, KInt index, KInt value) { + PrimitiveArraySet(thiz, index, value); +} + KInt Kotlin_IntArray_getArrayLength(KConstRef thiz) { const ArrayHeader* array = thiz->array(); return array->count_; @@ -572,10 +638,18 @@ KLong Kotlin_LongArray_get(KConstRef thiz, KInt index) { return PrimitiveArrayGet(thiz, index); } +KLong Kotlin_LongArray_get_without_BC(KConstRef thiz, KInt index) { + return PrimitiveArrayGet(thiz, index); +} + void Kotlin_LongArray_set(KRef thiz, KInt index, KLong value) { PrimitiveArraySet(thiz, index, value); } +void Kotlin_LongArray_set_without_BC(KRef thiz, KInt index, KLong value) { + PrimitiveArraySet(thiz, index, value); +} + KInt Kotlin_LongArray_getArrayLength(KConstRef thiz) { const ArrayHeader* array = thiz->array(); return array->count_; @@ -585,10 +659,18 @@ KFloat Kotlin_FloatArray_get(KConstRef thiz, KInt index) { return PrimitiveArrayGet(thiz, index); } +KFloat Kotlin_FloatArray_get_without_BC(KConstRef thiz, KInt index) { + return PrimitiveArrayGet(thiz, index); +} + void Kotlin_FloatArray_set(KRef thiz, KInt index, KFloat value) { PrimitiveArraySet(thiz, index, value); } +void Kotlin_FloatArray_set_without_BC(KRef thiz, KInt index, KFloat value) { + PrimitiveArraySet(thiz, index, value); +} + KInt Kotlin_FloatArray_getArrayLength(KConstRef thiz) { const ArrayHeader* array = thiz->array(); return array->count_; @@ -598,10 +680,18 @@ KDouble Kotlin_DoubleArray_get(KConstRef thiz, KInt index) { return PrimitiveArrayGet(thiz, index); } +KDouble Kotlin_DoubleArray_get_without_BC(KConstRef thiz, KInt index) { + return PrimitiveArrayGet(thiz, index); +} + void Kotlin_DoubleArray_set(KRef thiz, KInt index, KDouble value) { PrimitiveArraySet(thiz, index, value); } +void Kotlin_DoubleArray_set_without_BC(KRef thiz, KInt index, KDouble value) { + PrimitiveArraySet(thiz, index, value); +} + KInt Kotlin_DoubleArray_getArrayLength(KConstRef thiz) { const ArrayHeader* array = thiz->array(); return array->count_; @@ -611,10 +701,18 @@ KBoolean Kotlin_BooleanArray_get(KConstRef thiz, KInt index) { return PrimitiveArrayGet(thiz, index); } +KBoolean Kotlin_BooleanArray_get_without_BC(KConstRef thiz, KInt index) { + return PrimitiveArrayGet(thiz, index); +} + void Kotlin_BooleanArray_set(KRef thiz, KInt index, KBoolean value) { PrimitiveArraySet(thiz, index, value); } +void Kotlin_BooleanArray_set_without_BC(KRef thiz, KInt index, KBoolean value) { + PrimitiveArraySet(thiz, index, value); +} + KInt Kotlin_BooleanArray_getArrayLength(KConstRef thiz) { const ArrayHeader* array = thiz->array(); return array->count_; @@ -624,10 +722,18 @@ KNativePtr Kotlin_NativePtrArray_get(KConstRef thiz, KInt index) { return PrimitiveArrayGet(thiz, index); } +KNativePtr Kotlin_NativePtrArray_get_without_BC(KConstRef thiz, KInt index) { + return PrimitiveArrayGet(thiz, index); +} + void Kotlin_NativePtrArray_set(KRef thiz, KInt index, KNativePtr value) { PrimitiveArraySet(thiz, index, value); } +void Kotlin_NativePtrArray_set_without_BC(KRef thiz, KInt index, KNativePtr value) { + PrimitiveArraySet(thiz, index, value); +} + KInt Kotlin_NativePtrArray_getArrayLength(KConstRef thiz) { const ArrayHeader* array = thiz->array(); return array->count_;