Immutable data prototype. (#799)

This commit is contained in:
Nikolay Igotti
2017-08-22 16:21:10 +03:00
committed by GitHub
parent 87f2bed5c8
commit 109f84f9af
12 changed files with 215 additions and 15 deletions
@@ -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)
@@ -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
@@ -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)
@@ -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)
}
@@ -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 {
@@ -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)
}
@@ -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
@@ -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
}
})
+5
View File
@@ -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()
}