[K/N] Added functions for set/get array operatorswithout bounds check

This commit is contained in:
Elena Lepilkina
2021-06-04 12:27:47 +03:00
committed by Space
parent dd21326425
commit 2cb3a20733
7 changed files with 222 additions and 19 deletions
@@ -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)
@@ -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
@@ -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(
@@ -390,6 +390,7 @@ private val backendCodegen = namedUnitPhase(
name = "Backend codegen",
description = "Backend code generation",
lower = takeFromContext<Context, Unit, IrModuleFragment> { 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.
@@ -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))
}
}
}
@@ -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("<setWithoutBC>")
val getWithoutBC = Name.special("<getWithoutBC>")
}
// This is what Context collects about IR.
internal class KonanIr(context: Context, irModule: IrModuleFragment): Ir<Context>(context, irModule) {
override var symbols: KonanSymbols by Delegates.notNull()
+124 -18
View File
@@ -71,21 +71,57 @@ inline void copyImpl(KConstRef thiz, KInt fromIndex,
}
template <class T>
template <class T, bool BoundsCheck = true>
inline void PrimitiveArraySet(KRef thiz, KInt index, T value) {
ArrayHeader* array = thiz->array();
boundsCheck(array, index);
if (BoundsCheck)
boundsCheck(array, index);
mutabilityCheck(thiz);
*PrimitiveArrayAddressOfElementAt<T>(array, index) = value;
}
template <class T>
template <class T, bool BoundsCheck = true>
inline T PrimitiveArrayGet(KConstRef thiz, KInt index) {
const ArrayHeader* array = thiz->array();
boundsCheck(array, index);
if (BoundsCheck)
boundsCheck(array, index);
return *PrimitiveArrayAddressOfElementAt<T>(array, index);
}
template<bool BoundsCheck = true>
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<bool BoundsCheck = true>
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<bool BoundsCheck = true>
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<bool BoundsCheck = true>
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<false>(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<false>(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<false>(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<false>(thiz, index, value);
}
KInt Kotlin_ByteArray_getArrayLength(KConstRef thiz) {
@@ -447,10 +489,18 @@ KChar Kotlin_CharArray_get(KConstRef thiz, KInt index) {
return PrimitiveArrayGet<KChar>(thiz, index);
}
KChar Kotlin_CharArray_get_without_BC(KConstRef thiz, KInt index) {
return PrimitiveArrayGet<KChar, false>(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<KChar, false>(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<KShort>(thiz, index);
}
KShort Kotlin_ShortArray_get_without_BC(KConstRef thiz, KInt index) {
return PrimitiveArrayGet<KShort, false>(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<KShort, false>(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<KInt>(thiz, index);
}
KInt Kotlin_IntArray_get_without_BC(KConstRef thiz, KInt index) {
return PrimitiveArrayGet<KInt, false>(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<KInt, false>(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<KLong>(thiz, index);
}
KLong Kotlin_LongArray_get_without_BC(KConstRef thiz, KInt index) {
return PrimitiveArrayGet<KLong, false>(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<KLong, false>(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<KFloat>(thiz, index);
}
KFloat Kotlin_FloatArray_get_without_BC(KConstRef thiz, KInt index) {
return PrimitiveArrayGet<KFloat, false>(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<KFloat, false>(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<KDouble>(thiz, index);
}
KDouble Kotlin_DoubleArray_get_without_BC(KConstRef thiz, KInt index) {
return PrimitiveArrayGet<KDouble, false>(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<KDouble, false>(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<KBoolean>(thiz, index);
}
KBoolean Kotlin_BooleanArray_get_without_BC(KConstRef thiz, KInt index) {
return PrimitiveArrayGet<KBoolean, false>(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<KBoolean, false>(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<KNativePtr>(thiz, index);
}
KNativePtr Kotlin_NativePtrArray_get_without_BC(KConstRef thiz, KInt index) {
return PrimitiveArrayGet<KNativePtr, false>(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<KNativePtr, false>(thiz, index, value);
}
KInt Kotlin_NativePtrArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = thiz->array();
return array->count_;