backend: implement compile-time eval of varargs and listOf;
also perform some refactoring around.
This commit is contained in:
committed by
SvyatoslavScherbina
parent
e28a9c71a8
commit
415f2f1d35
+7
@@ -76,6 +76,8 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
fun load(value: LLVMValueRef, varName: String): LLVMValueRef = LLVMBuildLoad(builder, value, varName)!!
|
fun load(value: LLVMValueRef, varName: String): LLVMValueRef = LLVMBuildLoad(builder, value, varName)!!
|
||||||
fun store(value: LLVMValueRef, ptr: LLVMValueRef): LLVMValueRef = LLVMBuildStore(builder, value, ptr)!!
|
fun store(value: LLVMValueRef, ptr: LLVMValueRef): LLVMValueRef = LLVMBuildStore(builder, value, ptr)!!
|
||||||
|
|
||||||
|
fun isConst(value: LLVMValueRef): Boolean = (LLVMIsConstant(value) == 1)
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
fun invoke(llvmFunction: LLVMValueRef?, args: List<LLVMValueRef?>,
|
fun invoke(llvmFunction: LLVMValueRef?, args: List<LLVMValueRef?>,
|
||||||
@@ -124,6 +126,11 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
fun classType(descriptor: ClassDescriptor): LLVMTypeRef = LLVMGetTypeByName(context.llvmModule, descriptor.symbolName)!!
|
fun classType(descriptor: ClassDescriptor): LLVMTypeRef = LLVMGetTypeByName(context.llvmModule, descriptor.symbolName)!!
|
||||||
fun typeInfoValue(descriptor: ClassDescriptor): LLVMValueRef = descriptor.llvmTypeInfoPtr
|
fun typeInfoValue(descriptor: ClassDescriptor): LLVMValueRef = descriptor.llvmTypeInfoPtr
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pointer to type info for given type, or `null` if the type doesn't have corresponding type info.
|
||||||
|
*/
|
||||||
|
fun typeInfoValue(type: KotlinType): LLVMValueRef? = type.typeInfoPtr?.llvm
|
||||||
|
|
||||||
fun param(fn: FunctionDescriptor, i: Int): LLVMValueRef {
|
fun param(fn: FunctionDescriptor, i: Int): LLVMValueRef {
|
||||||
assert (i >= 0 && i < countParams(fn))
|
assert (i >= 0 && i < countParams(fn))
|
||||||
return LLVMGetParam(fn.llvmFunction, i)!!
|
return LLVMGetParam(fn.llvmFunction, i)!!
|
||||||
|
|||||||
+8
@@ -12,6 +12,8 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides utility methods to the implementer.
|
* Provides utility methods to the implementer.
|
||||||
@@ -94,6 +96,12 @@ internal interface ContextUtils {
|
|||||||
val ClassDescriptor.typeInfoPtr: ConstPointer
|
val ClassDescriptor.typeInfoPtr: ConstPointer
|
||||||
get() = constPointer(this.llvmTypeInfoPtr)
|
get() = constPointer(this.llvmTypeInfoPtr)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pointer to type info for this type, or `null` if the type doesn't have corresponding type info.
|
||||||
|
*/
|
||||||
|
val KotlinType.typeInfoPtr: ConstPointer?
|
||||||
|
get() = TypeUtils.getClassDescriptor(this)?.typeInfoPtr
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns contents of this [GlobalHash].
|
* Returns contents of this [GlobalHash].
|
||||||
*
|
*
|
||||||
|
|||||||
+67
-5
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
@@ -694,12 +695,30 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
private fun evaluateVararg(tmpVariableName: String, value: IrVararg): LLVMValueRef? {
|
private fun evaluateVararg(tmpVariableName: String, value: IrVararg): LLVMValueRef? {
|
||||||
val arrayCreationArgs = listOf(codegen.kTheArrayTypeInfo, kImmInt32One, Int32(value.elements.size).llvm)
|
val arguments = value.elements.map {
|
||||||
|
assert (it !is IrSpreadElement)
|
||||||
|
evaluateExpression(codegen.newVar(), it)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
return genCreateArray(tmpVariableName, value.type, arguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun genCreateArray(tmpVariableName: String,
|
||||||
|
arrayType: KotlinType, elements: List<LLVMValueRef>): LLVMValueRef {
|
||||||
|
|
||||||
|
if (elements.all { codegen.isConst(it) }) {
|
||||||
|
// Note: even if all elements are const, they aren't guaranteed to be statically initialized.
|
||||||
|
// E.g. an element may be a pointer to lazy-initialized object (aka singleton).
|
||||||
|
// However it is guaranteed that all elements are already initialized at this point.
|
||||||
|
return codegen.staticData.createKotlinArray(arrayType, elements)
|
||||||
|
}
|
||||||
|
|
||||||
|
val typeInfo = codegen.typeInfoValue(arrayType)!!
|
||||||
|
|
||||||
|
val arrayCreationArgs = listOf(typeInfo, kImmInt32One, Int32(elements.size).llvm)
|
||||||
val array = currentCodeContext.genCall(context.allocArrayFunction, arrayCreationArgs, tmpVariableName)
|
val array = currentCodeContext.genCall(context.allocArrayFunction, arrayCreationArgs, tmpVariableName)
|
||||||
value.elements.forEachIndexed { i, it ->
|
elements.forEachIndexed { i, it ->
|
||||||
val elementValueRaw = evaluateExpression(codegen.newVar(), it)
|
currentCodeContext.genCall(context.setArrayFunction, listOf(array, Int32(i).llvm, it), "")
|
||||||
currentCodeContext.genCall(context.setArrayFunction, listOf(array, Int32(i).llvm, elementValueRaw!!), "")
|
|
||||||
return@forEachIndexed
|
|
||||||
}
|
}
|
||||||
return array
|
return array
|
||||||
}
|
}
|
||||||
@@ -1367,11 +1386,54 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to evaluate given expression with given (already evaluated) arguments in compile time.
|
||||||
|
* Returns `null` on failure.
|
||||||
|
*/
|
||||||
|
private fun compileTimeEvaluate(expression: IrMemberAccessExpression, args: List<LLVMValueRef>): LLVMValueRef? {
|
||||||
|
if (!args.all { codegen.isConst(it) }) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val function = expression.descriptor
|
||||||
|
|
||||||
|
if (function.fqNameSafe.asString() == "kotlin.collections.listOf" && function.valueParameters.size == 1) {
|
||||||
|
val varargExpression = expression.getValueArgument(0) as? IrVararg
|
||||||
|
|
||||||
|
if (varargExpression != null) {
|
||||||
|
// The function is kotlin.collections.listOf<T>(vararg args: T).
|
||||||
|
// TODO: refer functions more reliably.
|
||||||
|
|
||||||
|
val vararg = args.single()
|
||||||
|
|
||||||
|
if (varargExpression.elements.any { it is IrSpreadElement }) {
|
||||||
|
return null // not supported yet, see `length` calculation below.
|
||||||
|
}
|
||||||
|
val length = varargExpression.elements.size
|
||||||
|
// TODO: store length in `vararg` itself when more abstract types will be used for values.
|
||||||
|
|
||||||
|
// `elementType` is type argument of function return type:
|
||||||
|
val elementType = function.returnType!!.arguments.single()
|
||||||
|
|
||||||
|
val array = constPointer(vararg)
|
||||||
|
// Note: dirty hack here: `vararg` has type `Array<out E>`, but `createArrayList` expects `Array<E>`;
|
||||||
|
// however `vararg` is immutable, and in current implementation it has type `Array<E>`,
|
||||||
|
// so let's ignore this mismatch currently for simplicity.
|
||||||
|
|
||||||
|
return context.staticData.createArrayList(elementType, array, length).llvm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
private fun evaluateCall(tmpVariableName: String, value: IrMemberAccessExpression): LLVMValueRef {
|
private fun evaluateCall(tmpVariableName: String, value: IrMemberAccessExpression): LLVMValueRef {
|
||||||
logger.log("evaluateCall : $tmpVariableName = ${ir2string(value)}")
|
logger.log("evaluateCall : $tmpVariableName = ${ir2string(value)}")
|
||||||
|
|
||||||
val args = evaluateExplicitArgs(value)
|
val args = evaluateExplicitArgs(value)
|
||||||
|
|
||||||
|
compileTimeEvaluate(value, args)?.let { return it }
|
||||||
|
|
||||||
when {
|
when {
|
||||||
value is IrDelegatingConstructorCall ->
|
value is IrDelegatingConstructorCall ->
|
||||||
return delegatingConstructorCall(tmpVariableName, value.descriptor, args)
|
return delegatingConstructorCall(tmpVariableName, value.descriptor, args)
|
||||||
|
|||||||
+6
-2
@@ -57,6 +57,8 @@ internal open class Struct(val type: LLVMTypeRef?, val elements: List<ConstValue
|
|||||||
|
|
||||||
constructor(type: LLVMTypeRef?, vararg elements: ConstValue) : this(type, elements.toList())
|
constructor(type: LLVMTypeRef?, vararg elements: ConstValue) : this(type, elements.toList())
|
||||||
|
|
||||||
|
constructor(vararg elements: ConstValue) : this(structType(elements.map { it.llvmType }), *elements)
|
||||||
|
|
||||||
override val llvm = memScoped {
|
override val llvm = memScoped {
|
||||||
val values = elements.map { it.llvm }.toTypedArray()
|
val values = elements.map { it.llvm }.toTypedArray()
|
||||||
val valuesNativeArrayPtr = allocArrayOf(*values)[0].ptr
|
val valuesNativeArrayPtr = allocArrayOf(*values)[0].ptr
|
||||||
@@ -128,8 +130,10 @@ internal val ContextUtils.kNullArrayHeaderPtr: LLVMValueRef
|
|||||||
|
|
||||||
internal fun pointerType(pointeeType: LLVMTypeRef) = LLVMPointerType(pointeeType, 0)!!
|
internal fun pointerType(pointeeType: LLVMTypeRef) = LLVMPointerType(pointeeType, 0)!!
|
||||||
|
|
||||||
internal fun structType(vararg types: LLVMTypeRef): LLVMTypeRef = memScoped {
|
internal fun structType(vararg types: LLVMTypeRef): LLVMTypeRef = structType(types.toList())
|
||||||
LLVMStructType(allocArrayOf(*types)[0].ptr, types.size, 0)!!
|
|
||||||
|
internal fun structType(types: List<LLVMTypeRef>): LLVMTypeRef = memScoped {
|
||||||
|
LLVMStructType(allocArrayOf(types)[0].ptr, types.size, 0)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ContextUtils.getLlvmFunctionType(function: FunctionDescriptor): LLVMTypeRef {
|
internal fun ContextUtils.getLlvmFunctionType(function: FunctionDescriptor): LLVMTypeRef {
|
||||||
|
|||||||
+6
-1
@@ -15,11 +15,16 @@ internal class StaticData(override val context: Context): ContextUtils {
|
|||||||
companion object {
|
companion object {
|
||||||
fun create(staticData: StaticData, type: LLVMTypeRef, name: String): Global {
|
fun create(staticData: StaticData, type: LLVMTypeRef, name: String): Global {
|
||||||
val module = staticData.context.llvmModule
|
val module = staticData.context.llvmModule
|
||||||
if (LLVMGetNamedGlobal(module, name) != null) {
|
if (name != "" && LLVMGetNamedGlobal(module, name) != null) {
|
||||||
throw IllegalArgumentException("Global '$name' already exists")
|
throw IllegalArgumentException("Global '$name' already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
val llvmGlobal = LLVMAddGlobal(module, type, name)!!
|
val llvmGlobal = LLVMAddGlobal(module, type, name)!!
|
||||||
|
|
||||||
|
if (name == "") {
|
||||||
|
LLVMSetLinkage(llvmGlobal, LLVMLinkage.LLVMPrivateLinkage)
|
||||||
|
}
|
||||||
|
|
||||||
return Global(staticData, llvmGlobal)
|
return Global(staticData, llvmGlobal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+113
-28
@@ -2,8 +2,13 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
|||||||
|
|
||||||
import llvm.*
|
import llvm.*
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.TypeProjection
|
||||||
|
import org.jetbrains.kotlin.types.replace
|
||||||
|
|
||||||
private fun StaticData.objHeader(containerOffsetNegative: Int, typeInfo: ConstPointer): Struct {
|
private fun StaticData.objHeader(containerOffsetNegative: Int, typeInfo: ConstPointer): Struct {
|
||||||
assert (containerOffsetNegative >= 0)
|
assert (containerOffsetNegative >= 0)
|
||||||
@@ -16,41 +21,121 @@ private fun StaticData.arrayHeader(containerOffsetNegative: Int, typeInfo: Const
|
|||||||
return Struct(runtime.arrayHeaderType, objHeader, Int32(length))
|
return Struct(runtime.arrayHeaderType, objHeader, Int32(length))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun requiredPadding(size: Int, align: Int): Int {
|
||||||
|
val rem = size % align
|
||||||
|
return (align - rem) % align
|
||||||
|
}
|
||||||
|
|
||||||
private fun StaticData.staticContainerHeader(): Struct {
|
private fun StaticData.staticContainerHeader(): Struct {
|
||||||
val CONTAINER_TAG_NOCOUNT = 1 // FIXME: copy-pasted from runtime
|
val CONTAINER_TAG_NOCOUNT = 1 // FIXME: copy-pasted from runtime
|
||||||
return Struct(runtime.containerHeaderType, Int32(CONTAINER_TAG_NOCOUNT))
|
val header = Struct(runtime.containerHeaderType, Int32(CONTAINER_TAG_NOCOUNT))
|
||||||
|
|
||||||
|
// ArrayHeader struct is represented as packed in LLVM;
|
||||||
|
// so add explicit padding to container's header to make its objects properly aligned:
|
||||||
|
val llvmSize = LLVMABISizeOfType(llvmTargetData, header.type).toInt()
|
||||||
|
val paddingSize = requiredPadding(llvmSize, 8)
|
||||||
|
val padding = ConstArray(int8Type, ByteArray(paddingSize).map { Int8(it) })
|
||||||
|
|
||||||
|
// TODO: handle such cases more generally by using C types alignments instead of LLVM ones.
|
||||||
|
|
||||||
|
return Struct(header, padding)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun StaticData.createKotlinStringLiteral(value: IrConst<String>): ConstPointer {
|
internal fun StaticData.createKotlinStringLiteral(value: IrConst<String>): ConstPointer {
|
||||||
val base64Str = value.value.globalHashBase64
|
val name = "kstr:" + value.value.globalHashBase64
|
||||||
val valueBytes = value.value.toByteArray(Charsets.UTF_8)
|
val elements = value.value.toByteArray(Charsets.UTF_8).map { Int8(it) }
|
||||||
|
|
||||||
val arrayCount = valueBytes.size
|
val objRef = createKotlinArray(value.type, elements)
|
||||||
val arrayType = LLVMArrayType(int8Type, arrayCount)
|
|
||||||
|
|
||||||
val compositeType = structType(runtime.containerHeaderType, runtime.arrayHeaderType, arrayType)
|
val res = createAlias(name, objRef)
|
||||||
|
|
||||||
// TODO: use C types alignments instead of LLVM ones
|
|
||||||
val global = this.createGlobal(compositeType, "kstrcont:$base64Str")
|
|
||||||
LLVMSetLinkage(global.llvmGlobal, LLVMLinkage.LLVMPrivateLinkage)
|
|
||||||
|
|
||||||
val containerHeader = staticContainerHeader()
|
|
||||||
|
|
||||||
val objHeaderPtr = global.pointer.getElementPtr(1)
|
|
||||||
val containerHeaderPtr = global.pointer.getElementPtr(0)
|
|
||||||
val containerOffsetNegative = objHeaderPtr.sub(containerHeaderPtr)
|
|
||||||
|
|
||||||
val stringClass = value.type.constructor.declarationDescriptor as ClassDescriptor
|
|
||||||
assert (stringClass.fqNameSafe.asString() == "kotlin.String")
|
|
||||||
val arrayHeader = arrayHeader(containerOffsetNegative, stringClass.typeInfoPtr, arrayCount)
|
|
||||||
|
|
||||||
val array = ConstArray(int8Type, valueBytes.map { Int8(it) } )
|
|
||||||
|
|
||||||
global.setInitializer(Struct(compositeType, containerHeader, arrayHeader, array))
|
|
||||||
|
|
||||||
val stringRef = objHeaderPtr.bitcast(getLLVMType(value.type))
|
|
||||||
val res = createAlias("kstr:$base64Str", stringRef)
|
|
||||||
LLVMSetLinkage(res.llvm, LLVMLinkage.LLVMWeakAnyLinkage)
|
LLVMSetLinkage(res.llvm, LLVMLinkage.LLVMWeakAnyLinkage)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun StaticData.createRef(type: KotlinType, objHeaderPtr: ConstPointer): ConstPointer {
|
||||||
|
val llvmType = getLLVMType(type)
|
||||||
|
return if (llvmType != objHeaderPtr.llvmType) {
|
||||||
|
objHeaderPtr.bitcast(llvmType)
|
||||||
|
} else {
|
||||||
|
objHeaderPtr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun StaticData.createKotlinArray(arrayType: KotlinType, elements: List<LLVMValueRef>) =
|
||||||
|
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
|
||||||
|
// (use [0 x i8] as body if there are no elements)
|
||||||
|
val arrayBody = ConstArray(bodyElementType, elements)
|
||||||
|
|
||||||
|
val containerHeader = staticContainerHeader()
|
||||||
|
|
||||||
|
val compositeType = structType(containerHeader.llvmType, runtime.arrayHeaderType, arrayBody.llvmType)
|
||||||
|
|
||||||
|
val global = this.createGlobal(compositeType, "")
|
||||||
|
|
||||||
|
val objHeaderPtr = global.pointer.getElementPtr(1)
|
||||||
|
val containerHeaderPtr = global.pointer.getElementPtr(0)
|
||||||
|
val containerOffsetNegative = objHeaderPtr.sub(containerHeaderPtr)
|
||||||
|
val arrayHeader = arrayHeader(containerOffsetNegative, typeInfo, elements.size)
|
||||||
|
|
||||||
|
global.setInitializer(Struct(compositeType, containerHeader, arrayHeader, arrayBody))
|
||||||
|
|
||||||
|
return createRef(arrayType, objHeaderPtr)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun StaticData.createKotlinObject(type: KotlinType, body: ConstValue): ConstPointer {
|
||||||
|
val typeInfo = type.typeInfoPtr!!
|
||||||
|
|
||||||
|
val containerHeader = staticContainerHeader()
|
||||||
|
val compositeType = structType(containerHeader.llvmType, runtime.objHeaderType, body.llvmType)
|
||||||
|
|
||||||
|
val global = this.createGlobal(compositeType, "")
|
||||||
|
|
||||||
|
val objHeaderPtr = global.pointer.getElementPtr(1)
|
||||||
|
val containerHeaderPtr = global.pointer.getElementPtr(0)
|
||||||
|
val containerOffsetNegative = objHeaderPtr.sub(containerHeaderPtr)
|
||||||
|
val objHeader = objHeader(containerOffsetNegative, typeInfo)
|
||||||
|
|
||||||
|
global.setInitializer(Struct(compositeType, containerHeader, objHeader, body))
|
||||||
|
|
||||||
|
return createRef(type, objHeaderPtr)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun StaticData.getArrayListClass(): ClassDescriptor {
|
||||||
|
val module = context.irModule.descriptor
|
||||||
|
val pkg = module.getPackage(FqName.fromSegments(listOf("kotlin", "collections")))
|
||||||
|
val classifier = pkg.memberScope.getContributedClassifier(Name.identifier("ArrayList"),
|
||||||
|
NoLookupLocation.FROM_BACKEND)
|
||||||
|
|
||||||
|
return classifier as ClassDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates static instance of `kotlin.collections.ArrayList<elementType>` with given values of fields.
|
||||||
|
*
|
||||||
|
* @param array value for `array: Array<E>` field.
|
||||||
|
* @param length value for `length: Int` field.
|
||||||
|
*/
|
||||||
|
internal fun StaticData.createArrayList(elementType: TypeProjection, array: ConstPointer, length: Int): ConstPointer {
|
||||||
|
val arrayListClass = getArrayListClass()
|
||||||
|
|
||||||
|
// type is ArrayList<elementType>:
|
||||||
|
val type = arrayListClass.defaultType.replace(listOf(elementType))
|
||||||
|
|
||||||
|
// FIXME: properly import body type from stdlib
|
||||||
|
|
||||||
|
val body = Struct(
|
||||||
|
array, // array: Array<E>
|
||||||
|
Int32(0), // offset: Int
|
||||||
|
Int32(length), // length: Int
|
||||||
|
NullPointer(kObjHeader) // backing: ArrayList<E>?
|
||||||
|
)
|
||||||
|
|
||||||
|
return createKotlinObject(type, body)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user