Immutable data prototype. (#799)
This commit is contained in:
+4
@@ -58,6 +58,10 @@ class KonanBuiltIns(storageManager: StorageManager) : KotlinBuiltIns(storageMana
|
||||
val nativePtrPlusLong by lazy { nativePtr.unsubstitutedMemberScope.getContributedFunctions("plus").single() }
|
||||
val nativePtrToLong by lazy { nativePtr.unsubstitutedMemberScope.getContributedFunctions("toLong").single() }
|
||||
val getNativeNullPtr by lazy { packageScope.getContributedFunctions("getNativeNullPtr").single() }
|
||||
val immutableBinaryBlobOf by lazy {
|
||||
builtInsModule.getPackage(FqName("konan")).memberScope.
|
||||
getContributedFunctions("immutableBinaryBlobOf").single()
|
||||
}
|
||||
|
||||
private fun MemberScope.getContributedClassifier(name: String) =
|
||||
this.getContributedClassifier(Name.identifier(name), NoLookupLocation.FROM_BUILTINS)
|
||||
|
||||
+2
-1
@@ -95,7 +95,8 @@ private val arrayTypes = setOf(
|
||||
"kotlin.LongArray",
|
||||
"kotlin.FloatArray",
|
||||
"kotlin.DoubleArray",
|
||||
"kotlin.BooleanArray"
|
||||
"kotlin.BooleanArray",
|
||||
"konan.ImmutableBinaryBlob"
|
||||
)
|
||||
|
||||
internal val ClassDescriptor.isIntrinsic: Boolean
|
||||
|
||||
+7
@@ -83,6 +83,13 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
|
||||
}
|
||||
}.toMap()
|
||||
|
||||
val immutableBinaryBlob = symbolTable.referenceClass(
|
||||
builtInsPackage("konan").getContributedClassifier(
|
||||
Name.identifier("ImmutableBinaryBlob"), NoLookupLocation.FROM_BACKEND
|
||||
) as ClassDescriptor
|
||||
)
|
||||
|
||||
val immutableBinaryBlobOf = symbolTable.referenceSimpleFunction(context.builtIns.immutableBinaryBlobOf)
|
||||
|
||||
val scheduleImpl = symbolTable.referenceSimpleFunction(context.interopBuiltIns.scheduleImplFunction)
|
||||
|
||||
|
||||
+28
-2
@@ -1383,6 +1383,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
private fun evaluateStringConst(value: IrConst<String>) =
|
||||
if (this.produceImmutableBinaryBlob) {
|
||||
context.llvm.staticData.createImmutableBinaryBlob(value)
|
||||
} else {
|
||||
context.llvm.staticData.kotlinStringLiteral(
|
||||
context.builtIns.stringType, value).llvm
|
||||
}
|
||||
|
||||
private fun evaluateConst(value: IrConst<*>): LLVMValueRef {
|
||||
context.log{"evaluateConst : ${ir2string(value)}"}
|
||||
@@ -1397,8 +1404,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
IrConstKind.Short -> return LLVMConstInt(LLVMInt16Type(), (value.value as Short).toLong(), 1)!!
|
||||
IrConstKind.Int -> return LLVMConstInt(LLVMInt32Type(), (value.value as Int).toLong(), 1)!!
|
||||
IrConstKind.Long -> return LLVMConstInt(LLVMInt64Type(), value.value as Long, 1)!!
|
||||
IrConstKind.String -> return context.llvm.staticData.kotlinStringLiteral(
|
||||
context.builtIns.stringType, value as IrConst<String>).llvm
|
||||
IrConstKind.String -> return evaluateStringConst(value as IrConst<String>)
|
||||
IrConstKind.Float -> return LLVMConstRealOfString(LLVMFloatType(), (value.value as Float).toString())!!
|
||||
IrConstKind.Double -> return LLVMConstRealOfString(LLVMDoubleType(), (value.value as Double).toString())!!
|
||||
}
|
||||
@@ -1757,16 +1763,30 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
private fun CallableDescriptor.returnsUnit() = returnType == context.builtIns.unitType && !isSuspend
|
||||
|
||||
|
||||
private var produceImmutableBinaryBlob: Boolean = false
|
||||
|
||||
/**
|
||||
* Evaluates all arguments of [expression] that are explicitly represented in the IR.
|
||||
* Returns results in the same order as LLVM function expects, assuming that all explicit arguments
|
||||
* exactly correspond to a tail of LLVM parameters.
|
||||
*/
|
||||
private fun evaluateExplicitArgs(expression: IrMemberAccessExpression): List<LLVMValueRef> {
|
||||
// TODO: remove this hack by properly implementing blobs in the frontend.
|
||||
if (expression.descriptor.original == context.builtIns.immutableBinaryBlobOf) {
|
||||
// As calls to immutableBinaryBlobOf() cannot be composed, it's OK to
|
||||
// have simple flag for that purpose.
|
||||
assert(!produceImmutableBinaryBlob)
|
||||
produceImmutableBinaryBlob = true
|
||||
}
|
||||
|
||||
val evaluatedArgs = expression.getArguments().map { (param, argExpr) ->
|
||||
param to evaluateExpression(argExpr)
|
||||
}.toMap()
|
||||
|
||||
if (produceImmutableBinaryBlob)
|
||||
produceImmutableBinaryBlob = false
|
||||
|
||||
val allValueParameters = expression.descriptor.allParameters
|
||||
|
||||
return allValueParameters.dropWhile { it !in evaluatedArgs }.map {
|
||||
@@ -1968,6 +1988,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
LLVMBuildSExt(functionGenerationContext.builder, intPtrValue, resultType, "")!!
|
||||
}
|
||||
}
|
||||
|
||||
context.builtIns.immutableBinaryBlobOf -> {
|
||||
// LLVM value is already computed when evaluating argument, just use it.
|
||||
args.single()
|
||||
}
|
||||
|
||||
interop.objCObjectInitFromPtr -> {
|
||||
genObjCObjectInitFromPtr(args)
|
||||
}
|
||||
|
||||
+11
-10
@@ -78,16 +78,17 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
}
|
||||
|
||||
private val arrayClasses = mapOf(
|
||||
"kotlin.Array" to -LLVMABISizeOfType(llvmTargetData, kObjHeaderPtr).toInt(),
|
||||
"kotlin.ByteArray" to -1,
|
||||
"kotlin.CharArray" to -2,
|
||||
"kotlin.ShortArray" to -2,
|
||||
"kotlin.IntArray" to -4,
|
||||
"kotlin.LongArray" to -8,
|
||||
"kotlin.FloatArray" to -4,
|
||||
"kotlin.DoubleArray" to -8,
|
||||
"kotlin.BooleanArray" to -1,
|
||||
"kotlin.String" to -2
|
||||
"kotlin.Array" to -LLVMABISizeOfType(llvmTargetData, kObjHeaderPtr).toInt(),
|
||||
"kotlin.ByteArray" to -1,
|
||||
"kotlin.CharArray" to -2,
|
||||
"kotlin.ShortArray" to -2,
|
||||
"kotlin.IntArray" to -4,
|
||||
"kotlin.LongArray" to -8,
|
||||
"kotlin.FloatArray" to -4,
|
||||
"kotlin.DoubleArray" to -8,
|
||||
"kotlin.BooleanArray" to -1,
|
||||
"kotlin.String" to -2,
|
||||
"konan.ImmutableBinaryBlob" to -1
|
||||
)
|
||||
|
||||
private fun getInstanceSize(classType: LLVMTypeRef?, className: FqName) : Int {
|
||||
|
||||
+10
@@ -160,3 +160,13 @@ internal class StaticData(override val context: Context): ContextUtils {
|
||||
fun kotlinStringLiteral(type: KotlinType, value: IrConst<String>) =
|
||||
stringLiterals.getOrPut(value.value) { createKotlinStringLiteral(type, value) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates static instance of `konan.ImmutableByteArray` with given values of elements.
|
||||
*
|
||||
* @param args data for constant creation.
|
||||
*/
|
||||
internal fun StaticData.createImmutableBinaryBlob(value: IrConst<String>): LLVMValueRef {
|
||||
val args = value.value.map { Int8(it.toByte()).llvm }
|
||||
return createKotlinArray(context.ir.symbols.immutableBinaryBlob.descriptor.defaultType, args)
|
||||
}
|
||||
+1
-1
@@ -68,7 +68,6 @@ internal fun StaticData.createKotlinArray(arrayType: KotlinType, elements: List<
|
||||
createKotlinArray(arrayType, elements.map { constValue(it) }).llvm
|
||||
|
||||
internal fun StaticData.createKotlinArray(arrayType: KotlinType, elements: List<ConstValue>): ConstPointer {
|
||||
|
||||
val typeInfo = arrayType.typeInfoPtr!!
|
||||
|
||||
val bodyElementType: LLVMTypeRef = elements.firstOrNull()?.llvmType ?: int8Type
|
||||
@@ -143,6 +142,7 @@ internal fun StaticData.createArrayList(elementType: TypeProjection, array: Cons
|
||||
return createKotlinObject(type, body)
|
||||
}
|
||||
|
||||
|
||||
internal fun StaticData.createUnitInstance(descriptor: ClassDescriptor,
|
||||
bodyType: LLVMTypeRef,
|
||||
typeInfo: ConstPointer
|
||||
|
||||
+39
-1
@@ -1,12 +1,17 @@
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrSpreadElement
|
||||
import org.jetbrains.kotlin.ir.expressions.IrVararg
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
@@ -14,6 +19,7 @@ import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
/**
|
||||
* This pass runs before inlining and performs the following additional transformations over some calls:
|
||||
* - Assertion call removal.
|
||||
* - Convert immutableBinaryBlobOf() arguments to special IrConst.
|
||||
*/
|
||||
internal class SpecialCallsLowering(val context: Context) : FileLoweringPass {
|
||||
|
||||
@@ -32,6 +38,38 @@ internal class SpecialCallsLowering(val context: Context) : FileLoweringPass {
|
||||
return IrCompositeImpl(expression.startOffset, expression.endOffset, expression.type)
|
||||
}
|
||||
|
||||
if (expression.symbol == context.ir.symbols.immutableBinaryBlobOf) {
|
||||
// Convert arguments of the binary blob to special IrConst<String> structure, so that
|
||||
// vararg lowering will not affect it.
|
||||
val args = expression.getValueArgument(0) as? IrVararg
|
||||
if (args == null) throw Error("varargs shall not be lowered yet")
|
||||
if (args.elements.any { it is IrSpreadElement }) {
|
||||
context.reportCompilationError("no spread elements allowed here", irFile, args)
|
||||
}
|
||||
val builder = StringBuilder()
|
||||
args.elements.forEach {
|
||||
if (it !is IrConst<*>) {
|
||||
context.reportCompilationError(
|
||||
"all elements of binary blob must be constants", irFile, it)
|
||||
}
|
||||
val value = when (it.kind) {
|
||||
IrConstKind.Short -> (it.value as Short).toInt()
|
||||
else ->
|
||||
context.reportCompilationError("incorrect value for binary data: $it.value", irFile, it)
|
||||
}
|
||||
if (value < 0 || value > 0xff)
|
||||
context.reportCompilationError("incorrect value for binary data: $value", irFile, it)
|
||||
// Luckily, all values in range 0x00 .. 0xff represent valid UTF-16 symbols,
|
||||
// block 0 (Basic Latin) and block 1 (Latin-1 Supplement) in
|
||||
// Basic Multilingual Plane, so we could just append data "as is".
|
||||
builder.append(value.toChar())
|
||||
}
|
||||
expression.putValueArgument(0, IrConstImpl<String>(
|
||||
expression.startOffset, expression.endOffset,
|
||||
context.ir.symbols.immutableBinaryBlob.descriptor.defaultType,
|
||||
IrConstKind.String, builder.toString()))
|
||||
}
|
||||
|
||||
return expression
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1081,6 +1081,11 @@ task array2(type: RunKonanTest) {
|
||||
source = "runtime/collections/array2.kt"
|
||||
}
|
||||
|
||||
task array3(type: RunKonanTest) {
|
||||
goldValue = "1 2 3 7 8 9 -128 -1 \n1 2 3 7 8 9 -128 -1 \n"
|
||||
source = "runtime/collections/array3.kt"
|
||||
}
|
||||
|
||||
task sort0(type: RunKonanTest) {
|
||||
goldValue = "[a, b, x]\n[-1, 0, 42, 239, 100500]\n"
|
||||
source = "runtime/collections/sort0.kt"
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import konan.*
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
val data = immutableBinaryBlobOf(0x1, 0x2, 0x3, 0x7, 0x8, 0x9, 0x80, 0xff)
|
||||
for (b in data) {
|
||||
print("$b ")
|
||||
}
|
||||
println()
|
||||
|
||||
val dataClone = data.toByteArray()
|
||||
dataClone.map { print("$it ") }
|
||||
println()
|
||||
}
|
||||
Reference in New Issue
Block a user