Merge branch 'master' into inline
This commit is contained in:
@@ -204,9 +204,13 @@ targetList.each { target ->
|
||||
'-runtime', project(':runtime').file("build/${target}/runtime.bc"),
|
||||
'-properties', project(':backend.native').file('konan.properties'),
|
||||
project(':runtime').file('src/main/kotlin'),
|
||||
project(':Interop:Runtime').file('src/main/kotlin'),
|
||||
project(':Interop:Runtime').file('src/native/kotlin'),
|
||||
*project.globalArgs)
|
||||
|
||||
inputs.dir(project(':runtime').file('src/main/kotlin'))
|
||||
inputs.dir(project(':Interop:Runtime').file('src/main/kotlin'))
|
||||
inputs.dir(project(':Interop:Runtime').file('src/native/kotlin'))
|
||||
outputs.file(project(':runtime').file("build/${target}/stdlib.kt.bc"))
|
||||
|
||||
dependsOn ":runtime:${target}Runtime"
|
||||
|
||||
@@ -62,6 +62,9 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
||||
put(LIBRARY_FILES,
|
||||
arguments.libraries.toNonNullList())
|
||||
|
||||
put(NATIVE_LIBRARY_FILES,
|
||||
arguments.nativeLibraries.toNonNullList())
|
||||
|
||||
// TODO: Collect all the explicit file names into an object
|
||||
// and teach the compiler to work with temporaries and -save-temps.
|
||||
val bitcodeFile = if (arguments.nolink) {
|
||||
|
||||
@@ -21,6 +21,10 @@ public class K2NativeCompilerArguments extends CommonCompilerArguments {
|
||||
@ValueDescription("<path>")
|
||||
public String[] libraries;
|
||||
|
||||
@Argument(value = "nativelibrary", alias = "nl", description = "Link with the native library")
|
||||
@ValueDescription("<path>")
|
||||
public String[] nativeLibraries;
|
||||
|
||||
@Argument(value = "nolink", description = "Don't link, just produce a bitcode file")
|
||||
public boolean nolink;
|
||||
|
||||
|
||||
+41
-30
@@ -1,38 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.common
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrLocalDelegatedProperty
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrValueAccessExpression
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import java.util.*
|
||||
|
||||
abstract class AbstractClosureRecorder : IrElementVisitorVoid {
|
||||
// TODO: synchronize with JVM BE
|
||||
class Closure(val capturedValues: List<ValueDescriptor>)
|
||||
|
||||
abstract class AbstractClosureAnnotator : IrElementVisitorVoid {
|
||||
protected abstract fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure)
|
||||
protected abstract fun recordClassClosure(classDescriptor: ClassDescriptor, closure: Closure)
|
||||
|
||||
private class ClosureBuilder(val owner: DeclarationDescriptor) {
|
||||
private abstract class ClosureBuilder(open val owner: DeclarationDescriptor) {
|
||||
val capturedValues = mutableSetOf<ValueDescriptor>()
|
||||
|
||||
fun buildClosure() = Closure(capturedValues.toList())
|
||||
@@ -43,12 +27,39 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid {
|
||||
|
||||
private fun <T : CallableDescriptor> fillInNestedClosure(destination: MutableSet<T>, nested: List<T>) {
|
||||
nested.filterTo(destination) {
|
||||
it.containingDeclaration != owner
|
||||
isExternal(it)
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun <T : CallableDescriptor> isExternal(valueDescriptor: T): Boolean
|
||||
}
|
||||
|
||||
private val closuresStack = ArrayDeque<ClosureBuilder>()
|
||||
private class FunctionClosureBuilder(override val owner: FunctionDescriptor) : ClosureBuilder(owner) {
|
||||
|
||||
override fun <T : CallableDescriptor> isExternal(valueDescriptor: T): Boolean =
|
||||
valueDescriptor.containingDeclaration != owner && valueDescriptor != owner.dispatchReceiverParameter
|
||||
}
|
||||
|
||||
private class ClassClosureBuilder(override val owner: ClassDescriptor) : ClosureBuilder(owner) {
|
||||
|
||||
override fun <T : CallableDescriptor> isExternal(valueDescriptor: T): Boolean {
|
||||
// TODO: replace with 'return valueDescriptor.containingDeclaration != owner' after constructors lowering.
|
||||
var declaration: DeclarationDescriptor? = valueDescriptor.containingDeclaration
|
||||
while (declaration != null && declaration != owner) {
|
||||
declaration = declaration.containingDeclaration
|
||||
}
|
||||
return declaration != owner
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private val closuresStack = mutableListOf<ClosureBuilder>()
|
||||
|
||||
private fun <E> MutableList<E>.push(element: E) = this.add(element)
|
||||
|
||||
private fun <E> MutableList<E>.pop() = this.removeAt(size - 1)
|
||||
|
||||
private fun <E> MutableList<E>.peek(): E? = if (size == 0) null else this[size - 1]
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
@@ -56,7 +67,7 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid {
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
val classDescriptor = declaration.descriptor
|
||||
val closureBuilder = ClosureBuilder(classDescriptor)
|
||||
val closureBuilder = ClassClosureBuilder(classDescriptor)
|
||||
|
||||
closuresStack.push(closureBuilder)
|
||||
declaration.acceptChildrenVoid(this)
|
||||
@@ -73,7 +84,7 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid {
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
val functionDescriptor = declaration.descriptor
|
||||
val closureBuilder = ClosureBuilder(functionDescriptor)
|
||||
val closureBuilder = FunctionClosureBuilder(functionDescriptor)
|
||||
|
||||
closuresStack.push(closureBuilder)
|
||||
declaration.acceptChildrenVoid(this)
|
||||
@@ -98,7 +109,7 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid {
|
||||
|
||||
if (closureBuilder != null) {
|
||||
val variableDescriptor = expression.descriptor
|
||||
if (variableDescriptor.containingDeclaration != closureBuilder.owner) {
|
||||
if (closureBuilder.isExternal(variableDescriptor)) {
|
||||
closureBuilder.capturedValues.add(variableDescriptor)
|
||||
}
|
||||
}
|
||||
@@ -106,4 +117,4 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid {
|
||||
expression.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+82
-43
@@ -16,28 +16,32 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.AbstractClosureRecorder
|
||||
import org.jetbrains.kotlin.backend.common.BackendContext
|
||||
import org.jetbrains.kotlin.backend.common.Closure
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||
import org.jetbrains.kotlin.ir.visitors.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.parents
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import java.util.*
|
||||
|
||||
class LocalDeclarationsLowering(val context: BackendContext): DeclarationContainerLoweringPass {
|
||||
class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContainerLoweringPass {
|
||||
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
||||
if (irDeclarationContainer is IrDeclaration &&
|
||||
irDeclarationContainer.descriptor.parents.any { it is CallableDescriptor }) {
|
||||
@@ -51,10 +55,13 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
lambdasCount = 0
|
||||
|
||||
irDeclarationContainer.declarations.transformFlat { memberDeclaration ->
|
||||
if (memberDeclaration is IrFunction)
|
||||
LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
|
||||
else
|
||||
null
|
||||
// TODO: may be do the opposite - specify the list of IR elements which need not to be transformed
|
||||
when (memberDeclaration) {
|
||||
is IrFunction -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
|
||||
is IrProperty -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
|
||||
is IrAnonymousInitializer -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +124,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
val fieldDescriptor = capturedValueToField[descriptor] ?: return null
|
||||
|
||||
return IrGetFieldImpl(startOffset, endOffset, fieldDescriptor,
|
||||
receiver = IrGetValueImpl(startOffset, endOffset, this.descriptor.thisAsReceiverParameter)
|
||||
receiver = IrGetValueImpl(startOffset, endOffset, this.descriptor.thisAsReceiverParameter)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -125,7 +132,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
"LocalClassContext for ${descriptor}"
|
||||
}
|
||||
|
||||
private inner class LocalDeclarationsTransformer(val memberFunction: IrFunction) {
|
||||
private inner class LocalDeclarationsTransformer(val memberDeclaration: IrDeclaration) {
|
||||
val localFunctions: MutableMap<FunctionDescriptor, LocalFunctionContext> = LinkedHashMap()
|
||||
val localClasses: MutableMap<ClassDescriptor, LocalClassContext> = LinkedHashMap()
|
||||
val localClassConstructors: MutableMap<ClassConstructorDescriptor, LocalClassConstructorContext> = LinkedHashMap()
|
||||
@@ -155,7 +162,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
|
||||
private fun collectRewrittenDeclarations(): ArrayList<IrDeclaration> =
|
||||
ArrayList<IrDeclaration>(localFunctions.size + localClasses.size + 1).apply {
|
||||
add(memberFunction)
|
||||
add(memberDeclaration)
|
||||
|
||||
localFunctions.values.mapTo(this) {
|
||||
val original = it.declaration
|
||||
@@ -174,8 +181,12 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
private inner class FunctionBodiesRewriter(val localContext: LocalContext?) : IrElementTransformerVoid() {
|
||||
|
||||
override fun visitClass(declaration: IrClass): IrStatement {
|
||||
// Replace local class definition with an empty composite.
|
||||
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
|
||||
if (declaration.descriptor in localClasses) {
|
||||
// Replace local class definition with an empty composite.
|
||||
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
|
||||
} else {
|
||||
return super.visitClass(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction): IrStatement {
|
||||
@@ -183,18 +194,20 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
// Replace local function definition with an empty composite.
|
||||
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
|
||||
} else {
|
||||
declaration.transformChildrenVoid(this)
|
||||
return declaration
|
||||
return super.visitFunction(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitConstructor(declaration: IrConstructor): IrStatement {
|
||||
// Body is transformed separately.
|
||||
|
||||
val transformedDescriptor = localClassConstructors[declaration.descriptor]!!.transformedDescriptor
|
||||
|
||||
return IrConstructorImpl(declaration.startOffset, declaration.endOffset, declaration.origin,
|
||||
transformedDescriptor, declaration.body!!)
|
||||
val transformedDescriptor = localClassConstructors[declaration.descriptor]?.transformedDescriptor
|
||||
if (transformedDescriptor != null) {
|
||||
return IrConstructorImpl(declaration.startOffset, declaration.endOffset, declaration.origin,
|
||||
transformedDescriptor, declaration.body!!)
|
||||
} else {
|
||||
return super.visitConstructor(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
@@ -222,6 +235,21 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
return newCall
|
||||
}
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
|
||||
val oldCallee = expression.descriptor.original
|
||||
val newCallee = transformedDescriptors[oldCallee] as ClassConstructorDescriptor? ?: return expression
|
||||
|
||||
val newExpression = IrDelegatingConstructorCallImpl(
|
||||
expression.startOffset, expression.endOffset,
|
||||
newCallee,
|
||||
remapTypeArguments(expression, newCallee)
|
||||
).fillArguments(expression)
|
||||
|
||||
return newExpression
|
||||
}
|
||||
|
||||
private fun <T : IrMemberAccessExpression> T.fillArguments(oldExpression: IrMemberAccessExpression): T {
|
||||
|
||||
mapValueParameters { newValueParameterDescriptor ->
|
||||
@@ -233,7 +261,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
// The callee expects captured value as argument.
|
||||
val capturedValueDescriptor =
|
||||
newParameterToCaptured[newValueParameterDescriptor] ?:
|
||||
throw AssertionError("Non-mapped parameter $newValueParameterDescriptor")
|
||||
throw AssertionError("Non-mapped parameter $newValueParameterDescriptor")
|
||||
|
||||
localContext?.irGet(
|
||||
oldExpression.startOffset, oldExpression.endOffset,
|
||||
@@ -292,8 +320,8 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
}
|
||||
}
|
||||
|
||||
private fun rewriteFunctionBody(irFunction: IrFunction, localContext: LocalContext?) {
|
||||
irFunction.transformChildrenVoid(FunctionBodiesRewriter(localContext))
|
||||
private fun rewriteFunctionBody(irDeclaration: IrDeclaration, localContext: LocalContext?) {
|
||||
irDeclaration.transformChildrenVoid(FunctionBodiesRewriter(localContext))
|
||||
}
|
||||
|
||||
private object DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE :
|
||||
@@ -339,7 +367,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
rewriteClassMembers(it.declaration, it)
|
||||
}
|
||||
|
||||
rewriteFunctionBody(memberFunction, null)
|
||||
rewriteFunctionBody(memberDeclaration, null)
|
||||
}
|
||||
|
||||
private fun createNewCall(oldCall: IrCall, newCallee: CallableDescriptor) =
|
||||
@@ -395,12 +423,12 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
.toList().reversed()
|
||||
.map { suggestLocalName(it) }
|
||||
.joinToString(separator = "$")
|
||||
)
|
||||
)
|
||||
|
||||
private fun createLiftedDescriptor(localFunctionContext: LocalFunctionContext) {
|
||||
val oldDescriptor = localFunctionContext.descriptor
|
||||
|
||||
val memberOwner = memberFunction.descriptor.containingDeclaration
|
||||
val memberOwner = memberDeclaration.descriptor.containingDeclaration!!
|
||||
val newDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||
memberOwner,
|
||||
oldDescriptor.annotations,
|
||||
@@ -480,7 +508,15 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
// Do not substitute type parameters for now.
|
||||
val newTypeParameters = oldDescriptor.typeParameters
|
||||
|
||||
val capturedValues = localClassContext.closure.capturedValues
|
||||
val capturedValues = mutableListOf<ValueDescriptor>()
|
||||
var classDescriptor = oldDescriptor.containingDeclaration
|
||||
while (true) {
|
||||
// Capture all values from the hierarchy since we need to call constructor of super class
|
||||
// with his captured values.
|
||||
val context = localClasses[classDescriptor] ?: break
|
||||
capturedValues.addAll(context.closure.capturedValues)
|
||||
classDescriptor = classDescriptor.getSuperClassOrAny()
|
||||
}
|
||||
|
||||
val newValueParameters = createTransformedValueParameters(localFunctionContext, capturedValues)
|
||||
|
||||
@@ -560,8 +596,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
if (valueDescriptor.name.isSpecial) {
|
||||
val oldNameStr = valueDescriptor.name.asString()
|
||||
Name.identifier("$" + oldNameStr.substring(1, oldNameStr.length - 1))
|
||||
}
|
||||
else
|
||||
} else
|
||||
valueDescriptor.name
|
||||
|
||||
private fun createUnsubstitutedCapturedValueParameter(
|
||||
@@ -586,7 +621,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
|
||||
|
||||
private fun collectClosures() {
|
||||
memberFunction.acceptChildrenVoid(object : AbstractClosureRecorder() {
|
||||
memberDeclaration.acceptChildrenVoid(object : AbstractClosureAnnotator() {
|
||||
override fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure) {
|
||||
localFunctions[functionDescriptor]?.closure = closure
|
||||
}
|
||||
@@ -598,16 +633,17 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
}
|
||||
|
||||
private fun collectLocalDeclarations() {
|
||||
memberFunction.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
memberDeclaration.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.isClassMember() = when (this.containingDeclaration) {
|
||||
is CallableDescriptor -> false
|
||||
is ClassDescriptor -> true
|
||||
else -> TODO(this.toString())
|
||||
private fun DeclarationDescriptor.declaredInFunction() = when (this.containingDeclaration) {
|
||||
is CallableDescriptor -> true
|
||||
is ClassDescriptor -> false
|
||||
is PackageFragmentDescriptor -> false
|
||||
else -> TODO(this.toString() + "\n" + this.containingDeclaration.toString())
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
@@ -615,7 +651,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
|
||||
val descriptor = declaration.descriptor
|
||||
|
||||
if (!descriptor.isClassMember()) {
|
||||
if (descriptor.declaredInFunction()) {
|
||||
val localFunctionContext = LocalFunctionContext(declaration)
|
||||
|
||||
localFunctions[descriptor] = localFunctionContext
|
||||
@@ -631,7 +667,9 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
declaration.acceptChildrenVoid(this)
|
||||
|
||||
val descriptor = declaration.descriptor
|
||||
assert (descriptor.isClassMember())
|
||||
assert(!descriptor.declaredInFunction())
|
||||
|
||||
if (descriptor.constructedClass.isInner) return
|
||||
|
||||
localClassConstructors[descriptor] = LocalClassConstructorContext(declaration)
|
||||
}
|
||||
@@ -641,12 +679,13 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
||||
|
||||
val descriptor = declaration.descriptor
|
||||
|
||||
if (descriptor.isClassMember()) {
|
||||
assert (descriptor.isInner)
|
||||
} else {
|
||||
val localClassContext = LocalClassContext(declaration)
|
||||
localClasses[descriptor] = localClassContext
|
||||
}
|
||||
if (descriptor.isInner) return
|
||||
|
||||
// Local nested classes can only be inner.
|
||||
assert(descriptor.declaredInFunction())
|
||||
|
||||
val localClassContext = LocalClassContext(declaration)
|
||||
localClasses[descriptor] = localClassContext
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+5
@@ -3,6 +3,7 @@ package org.jetbrains.kotlin.backend.konan
|
||||
import llvm.LLVMDumpModule
|
||||
import llvm.LLVMModuleRef
|
||||
import org.jetbrains.kotlin.backend.jvm.descriptors.initialize
|
||||
import org.jetbrains.kotlin.backend.konan.InteropBuiltIns
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.deepPrint
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
|
||||
import org.jetbrains.kotlin.backend.konan.ir.Ir
|
||||
@@ -57,6 +58,10 @@ internal final class Context(val config: KonanConfig) : KonanBackendContext() {
|
||||
override val irBuiltIns
|
||||
get() = ir.irModule.irBuiltins
|
||||
|
||||
val interopBuiltIns by lazy {
|
||||
InteropBuiltIns(this.builtIns)
|
||||
}
|
||||
|
||||
var llvmModule: LLVMModuleRef? = null
|
||||
set(module: LLVMModuleRef?) {
|
||||
if (field != null) {
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
package org.jetbrains.kotlin.backend.konan
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
|
||||
private val cPointerName = "CPointer"
|
||||
private val nativePointedName = "NativePointed"
|
||||
private val nativePtrName = "NativePtr"
|
||||
|
||||
internal class InteropBuiltIns(builtIns: KonanBuiltIns) {
|
||||
|
||||
object FqNames {
|
||||
val packageName = FqName("kotlinx.cinterop")
|
||||
|
||||
val nativePtr = packageName.child(Name.identifier(nativePtrName)).toUnsafe()
|
||||
val cPointer = packageName.child(Name.identifier(cPointerName)).toUnsafe()
|
||||
val nativePointed = packageName.child(Name.identifier(nativePointedName)).toUnsafe()
|
||||
}
|
||||
|
||||
private val packageScope = builtIns.builtInsModule.getPackage(FqNames.packageName).memberScope
|
||||
|
||||
val getNativeNullPtr = packageScope.getContributedFunctions("getNativeNullPtr").single()
|
||||
|
||||
val getPointerSize = packageScope.getContributedFunctions("getPointerSize").single()
|
||||
|
||||
val nullableInteropValueTypes = listOf(ValueType.C_POINTER, ValueType.NATIVE_POINTED)
|
||||
|
||||
private val nativePtr = packageScope.getContributedClassifier(nativePtrName) as ClassDescriptor
|
||||
|
||||
private val nativePointed = packageScope.getContributedClassifier(nativePointedName) as ClassDescriptor
|
||||
|
||||
private val cPointer = this.packageScope.getContributedClassifier(cPointerName) as ClassDescriptor
|
||||
|
||||
val cPointerRawValue = cPointer.unsubstitutedMemberScope.getContributedVariables("rawValue").single()
|
||||
|
||||
val nativePointedRawPtrGetter =
|
||||
nativePointed.unsubstitutedMemberScope.getContributedVariables("rawPtr").single().getter!!
|
||||
|
||||
val memberAt = packageScope.getContributedFunctions("memberAt").single()
|
||||
|
||||
val interpretPointed = packageScope.getContributedFunctions("interpretPointed").single()
|
||||
|
||||
val arrayGetByIntIndex = packageScope.getContributedFunctions("get").single {
|
||||
KotlinBuiltIns.isInt(it.valueParameters.single().type)
|
||||
}
|
||||
|
||||
val arrayGetByLongIndex = packageScope.getContributedFunctions("get").single {
|
||||
KotlinBuiltIns.isLong(it.valueParameters.single().type)
|
||||
}
|
||||
|
||||
val allocUninitializedArrayWithIntLength = packageScope.getContributedFunctions("allocArray").single {
|
||||
it.valueParameters.size == 1 && KotlinBuiltIns.isInt(it.valueParameters[0].type)
|
||||
}
|
||||
|
||||
val allocUninitializedArrayWithLongLength = packageScope.getContributedFunctions("allocArray").single {
|
||||
it.valueParameters.size == 1 && KotlinBuiltIns.isLong(it.valueParameters[0].type)
|
||||
}
|
||||
|
||||
val allocVariable = packageScope.getContributedFunctions("alloc").single {
|
||||
it.valueParameters.size == 0
|
||||
}
|
||||
|
||||
val typeOf = packageScope.getContributedFunctions("typeOf").single()
|
||||
|
||||
val variableClass = packageScope.getContributedClassifier("CVariable") as ClassDescriptor
|
||||
|
||||
val variableTypeClass =
|
||||
variableClass.unsubstitutedInnerClassesScope.getContributedClassifier("Type") as ClassDescriptor
|
||||
|
||||
val variableTypeSize = variableTypeClass.unsubstitutedMemberScope.getContributedVariables("size").single()
|
||||
|
||||
val variableTypeAlign = variableTypeClass.unsubstitutedMemberScope.getContributedVariables("align").single()
|
||||
|
||||
val nativeMemUtils = packageScope.getContributedClassifier("nativeMemUtils") as ClassDescriptor
|
||||
|
||||
private val primitives = listOf(
|
||||
builtIns.byte, builtIns.short, builtIns.int, builtIns.long,
|
||||
builtIns.float, builtIns.double,
|
||||
nativePtr
|
||||
)
|
||||
|
||||
val readPrimitive = primitives.map {
|
||||
nativeMemUtils.unsubstitutedMemberScope.getContributedFunctions("get" + it.name).single()
|
||||
}.toSet()
|
||||
|
||||
val writePrimitive = primitives.map {
|
||||
nativeMemUtils.unsubstitutedMemberScope.getContributedFunctions("put" + it.name).single()
|
||||
}.toSet()
|
||||
|
||||
val nativePtrPlusLong = nativePtr.unsubstitutedMemberScope.getContributedFunctions("plus").single()
|
||||
|
||||
}
|
||||
|
||||
private fun MemberScope.getContributedVariables(name: String) =
|
||||
this.getContributedVariables(Name.identifier(name), NoLookupLocation.FROM_BUILTINS)
|
||||
|
||||
private fun MemberScope.getContributedClassifier(name: String) =
|
||||
this.getContributedClassifier(Name.identifier(name), NoLookupLocation.FROM_BUILTINS)
|
||||
|
||||
private fun MemberScope.getContributedFunctions(name: String) =
|
||||
this.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BUILTINS)
|
||||
+3
@@ -29,6 +29,9 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
|
||||
private val loadedDescriptors = loadLibMetadata(libraries)
|
||||
|
||||
internal val librariesToLink: List<String>
|
||||
get() = libraries + configuration.getList(KonanConfigKeys.NATIVE_LIBRARY_FILES)
|
||||
|
||||
val moduleId: String
|
||||
get() = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME)
|
||||
|
||||
|
||||
+2
@@ -7,6 +7,8 @@ class KonanConfigKeys {
|
||||
companion object {
|
||||
val LIBRARY_FILES: CompilerConfigurationKey<List<String>>
|
||||
= CompilerConfigurationKey.create("library file paths")
|
||||
val NATIVE_LIBRARY_FILES: CompilerConfigurationKey<List<String>>
|
||||
= CompilerConfigurationKey.create("native library file paths")
|
||||
val BITCODE_FILE: CompilerConfigurationKey<String>
|
||||
= CompilerConfigurationKey.create("emitted bitcode file path")
|
||||
val EXECUTABLE_FILE: CompilerConfigurationKey<String>
|
||||
|
||||
+3
-3
@@ -23,9 +23,6 @@ internal class KonanLower(val context: Context) {
|
||||
phaser.phase(KonanPhase.LOWER_ENUMS) {
|
||||
EnumClassLowering(context).run(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.LOWER_INNER_CLASSES) {
|
||||
InnerClassLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.LOWER_VARARG) {
|
||||
VarargInjectionLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
@@ -45,6 +42,9 @@ internal class KonanLower(val context: Context) {
|
||||
phaser.phase(KonanPhase.LOWER_LOCAL_FUNCTIONS) {
|
||||
LocalDeclarationsLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.LOWER_INNER_CLASSES) {
|
||||
InnerClassLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.LOWER_CALLABLES) {
|
||||
CallableReferenceLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
|
||||
+1
@@ -18,6 +18,7 @@ enum class KonanPhase(val description: String,
|
||||
/* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering"),
|
||||
/* ... ... */ LOWER_CALLABLES("Callable references Lowering"),
|
||||
/* ... ... */ LOWER_INLINE("Functions inlining"),
|
||||
/* ... ... */ LOWER_INTEROP("Interop lowering"),
|
||||
/* ... ... */ AUTOBOX("Autoboxing of primitive types"),
|
||||
/* ... ... */ LOWER_ENUMS("Enum classes lowering"),
|
||||
/* ... ... */ LOWER_INNER_CLASSES("Inner classes lowering"),
|
||||
|
||||
+1
-1
@@ -144,7 +144,7 @@ internal class LinkStage(val context: Context) {
|
||||
val optimize = config.get(KonanConfigKeys.OPTIMIZATION) ?: false
|
||||
val emitted = config.get(KonanConfigKeys.BITCODE_FILE)!!
|
||||
val nostdlib = config.get(KonanConfigKeys.NOSTDLIB) ?: false
|
||||
val libraries = context.config.libraries
|
||||
val libraries = context.config.librariesToLink
|
||||
|
||||
fun llvmLto(files: List<BitcodeFile>): ObjectFile {
|
||||
val tmpCombined = File.createTempFile("combined", ".o")
|
||||
|
||||
+5
-1
@@ -24,7 +24,11 @@ enum class ValueType(val classFqName: FqNameUnsafe, val isNullable: Boolean = fa
|
||||
FLOAT(KotlinBuiltIns.FQ_NAMES._float),
|
||||
DOUBLE(KotlinBuiltIns.FQ_NAMES._double),
|
||||
|
||||
UNBOUND_CALLABLE_REFERENCE(FqNameUnsafe("konan.internal.UnboundCallableReference"))
|
||||
UNBOUND_CALLABLE_REFERENCE(FqNameUnsafe("konan.internal.UnboundCallableReference")),
|
||||
NATIVE_PTR(InteropBuiltIns.FqNames.nativePtr),
|
||||
|
||||
NATIVE_POINTED(InteropBuiltIns.FqNames.nativePointed, isNullable = true),
|
||||
C_POINTER(InteropBuiltIns.FqNames.cPointer, isNullable = true)
|
||||
}
|
||||
|
||||
private fun KotlinType.isConstructedFromGivenClass(fqName: FqNameUnsafe) =
|
||||
|
||||
+2
@@ -65,6 +65,8 @@ internal fun IrMemberAccessExpression.addArguments(args: Map<ParameterDescriptor
|
||||
internal fun IrMemberAccessExpression.addArguments(args: List<Pair<ParameterDescriptor, IrExpression>>) =
|
||||
this.addArguments(args.toMap())
|
||||
|
||||
internal fun IrExpression.isNullConst() = this is IrConst<*> && this.kind == IrConstKind.Null
|
||||
|
||||
fun ir2string(ir: IrElement?): String = ir2stringWhole(ir).takeWhile { it != '\n' }
|
||||
|
||||
fun ir2stringWhole(ir: IrElement?): String {
|
||||
|
||||
+3
-1
@@ -15,7 +15,9 @@ private val valueTypes = ValueType.values().associate {
|
||||
ValueType.LONG -> LLVMInt64Type()
|
||||
ValueType.FLOAT -> LLVMFloatType()
|
||||
ValueType.DOUBLE -> LLVMDoubleType()
|
||||
ValueType.UNBOUND_CALLABLE_REFERENCE -> int8TypePtr
|
||||
|
||||
ValueType.UNBOUND_CALLABLE_REFERENCE,
|
||||
ValueType.NATIVE_PTR, ValueType.NATIVE_POINTED, ValueType.C_POINTER -> int8TypePtr
|
||||
}!!
|
||||
}
|
||||
|
||||
|
||||
+24
-17
@@ -625,7 +625,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
private fun evaluateExpression(value: IrExpression): LLVMValueRef {
|
||||
when (value) {
|
||||
is IrSetterCallImpl -> return evaluateSetterCall (value)
|
||||
is IrTypeOperatorCall -> return evaluateTypeOperator (value)
|
||||
is IrCall -> return evaluateCall (value)
|
||||
is IrDelegatingConstructorCall ->
|
||||
@@ -1742,18 +1741,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
return callDirect(descriptor, args, resultLifetime)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateSetterCall(value: IrSetterCallImpl): LLVMValueRef {
|
||||
val descriptor = value.descriptor as FunctionDescriptor
|
||||
val args = mutableListOf<LLVMValueRef>()
|
||||
if (descriptor.dispatchReceiverParameter != null)
|
||||
args.add(evaluateExpression(value.dispatchReceiver!!)) //add this ptr
|
||||
args.add(evaluateExpression(value.getValueArgument(0)!!))
|
||||
return evaluateSimpleFunctionCall(
|
||||
descriptor, args, Lifetime.IRRELEVANT, value.superQualifier)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
private fun resultLifetime(callee: IrMemberAccessExpression): Lifetime {
|
||||
return resultLifetimes.getOrElse(callee) { Lifetime.GLOBAL }
|
||||
@@ -1779,16 +1766,16 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateIntrinsicCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val descriptor = callee.descriptor
|
||||
val descriptor = callee.descriptor.original
|
||||
val name = descriptor.fqNameUnsafe.asString()
|
||||
|
||||
return when (name) {
|
||||
when (name) {
|
||||
"konan.internal.areEqualByValue" -> {
|
||||
val arg0 = args[0]
|
||||
val arg1 = args[1]
|
||||
assert (arg0.type == arg1.type)
|
||||
|
||||
when (LLVMGetTypeKind(arg0.type)) {
|
||||
return when (LLVMGetTypeKind(arg0.type)) {
|
||||
LLVMTypeKind.LLVMFloatTypeKind, LLVMTypeKind.LLVMDoubleTypeKind ->
|
||||
codegen.fcmpEq(arg0, arg1)
|
||||
|
||||
@@ -1796,8 +1783,28 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
codegen.icmpEq(arg0, arg1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> TODO(name)
|
||||
val interop = context.interopBuiltIns
|
||||
|
||||
return when (descriptor) {
|
||||
in interop.readPrimitive -> {
|
||||
val pointerType = pointerType(codegen.getLLVMType(descriptor.returnType!!))
|
||||
val rawPointer = args.last()
|
||||
val pointer = codegen.bitcast(pointerType, rawPointer)
|
||||
codegen.load(pointer)
|
||||
}
|
||||
in interop.writePrimitive -> {
|
||||
val pointerType = pointerType(codegen.getLLVMType(descriptor.valueParameters.last().type))
|
||||
val rawPointer = args[1]
|
||||
val pointer = codegen.bitcast(pointerType, rawPointer)
|
||||
codegen.store(args[2], pointer)
|
||||
codegen.theUnitInstanceRef.llvm
|
||||
}
|
||||
interop.nativePtrPlusLong -> codegen.gep(args[0], args[1])
|
||||
interop.getNativeNullPtr -> kNullInt8Ptr
|
||||
interop.getPointerSize -> Int32(LLVMPointerSize(codegen.llvmTargetData)).llvm
|
||||
else -> TODO(callee.descriptor.original.toString())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
@@ -6,8 +6,10 @@ import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.ValueType
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalClass
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions
|
||||
import org.jetbrains.kotlin.backend.konan.ir.isNullConst
|
||||
import org.jetbrains.kotlin.backend.konan.notNullableIsRepresentedAs
|
||||
import org.jetbrains.kotlin.backend.konan.isRepresentedAs
|
||||
import org.jetbrains.kotlin.backend.konan.util.atMostOne
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
@@ -103,6 +105,10 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
|
||||
}
|
||||
|
||||
override fun IrExpression.useAs(type: KotlinType): IrExpression {
|
||||
val interop = context.interopBuiltIns
|
||||
if (this.isNullConst() && interop.nullableInteropValueTypes.any { type.isRepresentedAs(it) }) {
|
||||
return IrCallImpl(startOffset, endOffset, interop.getNativeNullPtr).uncheckedCast(type)
|
||||
}
|
||||
|
||||
val actualType = when (this) {
|
||||
is IrCall -> this.descriptor.original.returnType ?: this.type
|
||||
@@ -176,6 +182,14 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
|
||||
}
|
||||
|
||||
private fun IrExpression.unbox(valueType: ValueType): IrExpression {
|
||||
val unboxFunctionName = "unbox${valueType.shortName}"
|
||||
|
||||
context.builtIns.getKonanInternalFunctions(unboxFunctionName).atMostOne()?.let {
|
||||
return IrCallImpl(startOffset, endOffset, it).apply {
|
||||
putValueArgument(0, this@unbox.uncheckedCast(it.valueParameters[0].type))
|
||||
}.uncheckedCast(this.type)
|
||||
}
|
||||
|
||||
val boxGetter = getBoxType(valueType)
|
||||
.memberScope.getContributedDescriptors()
|
||||
.filterIsInstance<PropertyDescriptor>()
|
||||
|
||||
+10
-2
@@ -3,6 +3,8 @@ package org.jetbrains.kotlin.backend.konan.lower
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalFunctions
|
||||
import org.jetbrains.kotlin.backend.konan.ir.isNullConst
|
||||
import org.jetbrains.kotlin.backend.konan.util.atMostOne
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
@@ -69,9 +71,15 @@ private class BuiltinOperatorTransformer(val context: Context) : IrElementTransf
|
||||
// and thus can be declared synthetically in the compiler instead of explicitly in the runtime.
|
||||
|
||||
// Find a type-compatible `konan.internal.areEqualByValue` intrinsic:
|
||||
val equals = builtIns.getKonanInternalFunctions("areEqualByValue").firstOrNull {
|
||||
val equals = builtIns.getKonanInternalFunctions("areEqualByValue").atMostOne {
|
||||
lhs.type.isSubtypeOf(it.valueParameters[0].type) && rhs.type.isSubtypeOf(it.valueParameters[1].type)
|
||||
} ?: builtIns.getKonanInternalFunctions("areEqual").single() // or use the general implementation.
|
||||
} ?: if (lhs.isNullConst() || rhs.isNullConst()) {
|
||||
// or compare by reference if left or right part is `null`:
|
||||
irBuiltins.eqeqeq
|
||||
} else {
|
||||
// or use the general implementation:
|
||||
builtIns.getKonanInternalFunctions("areEqual").single()
|
||||
}
|
||||
|
||||
return IrCallImpl(startOffset, endOffset, equals).apply {
|
||||
putValueArgument(0, lhs)
|
||||
|
||||
+2
-2
@@ -69,7 +69,7 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
|
||||
if (instanceInitializerIndex >= 0) {
|
||||
// Initializing constructor: initialize 'this.this$0' with '$outer'.
|
||||
blockBody.statements.add(
|
||||
instanceInitializerIndex,
|
||||
0,
|
||||
IrSetFieldImpl(
|
||||
startOffset, endOffset, outerThisFieldDescriptor,
|
||||
IrGetValueImpl(startOffset, endOffset, classDescriptor.thisAsReceiverParameter),
|
||||
@@ -117,7 +117,7 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
|
||||
val outerThisField = context.specialDescriptorsFactory.getOuterThisFieldDescriptor(innerClass)
|
||||
irThis = IrGetFieldImpl(startOffset, endOffset, outerThisField, irThis, origin)
|
||||
|
||||
val outer = classDescriptor.containingDeclaration
|
||||
val outer = innerClass.containingDeclaration
|
||||
innerClass = outer as? ClassDescriptor ?:
|
||||
throw AssertionError("Unexpected containing declaration for inner class $innerClass: $outer")
|
||||
}
|
||||
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.at
|
||||
import org.jetbrains.kotlin.backend.common.lower.createFunctionIrBuilder
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.ValueType
|
||||
import org.jetbrains.kotlin.backend.konan.isRepresentedAs
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.builders.IrBuilder
|
||||
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
|
||||
/**
|
||||
* Lowers some interop intrinsic calls.
|
||||
*/
|
||||
internal class InteropLowering(val context: Context) : FunctionLoweringPass {
|
||||
override fun lower(irFunction: IrFunction) {
|
||||
val transformer = InteropTransformer(context, irFunction.descriptor)
|
||||
irFunction.transformChildrenVoid(transformer)
|
||||
}
|
||||
}
|
||||
|
||||
private class InteropTransformer(val context: Context, val function: FunctionDescriptor) : IrElementTransformerVoid() {
|
||||
|
||||
val builder = context.createFunctionIrBuilder(function)
|
||||
val interop = context.interopBuiltIns
|
||||
|
||||
private fun MemberScope.getSingleContributedFunction(name: String,
|
||||
predicate: (SimpleFunctionDescriptor) -> Boolean) =
|
||||
this.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).single(predicate)
|
||||
|
||||
private fun IrBuilder.irGetObject(descriptor: ClassDescriptor): IrExpression {
|
||||
return IrGetObjectValueImpl(startOffset, endOffset, descriptor.defaultType, descriptor)
|
||||
}
|
||||
|
||||
private fun IrBuilder.typeOf(descriptor: ClassDescriptor): IrExpression {
|
||||
val companionObject = descriptor.companionObjectDescriptor ?:
|
||||
error("native variable class $descriptor must have the companion object")
|
||||
// TODO: add more checks and produce the compile error instead of exception.
|
||||
|
||||
return irGetObject(companionObject)
|
||||
}
|
||||
|
||||
private fun IrBuilder.typeOf(type: KotlinType): IrExpression? {
|
||||
val descriptor = TypeUtils.getClassDescriptor(type) ?: return null
|
||||
return typeOf(descriptor)
|
||||
}
|
||||
|
||||
private fun KotlinType.findOverride(property: PropertyDescriptor): PropertyDescriptor {
|
||||
val result = this.memberScope.getContributedVariables(property.name, NoLookupLocation.FROM_BACKEND).single()
|
||||
assert (OverridingUtil.overrides(result, property))
|
||||
return result
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.sizeOf(typeObject: IrExpression): IrExpression {
|
||||
val sizeProperty = typeObject.type.findOverride(interop.variableTypeSize)
|
||||
return irGet(typeObject, sizeProperty)
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.sizeOf(type: KotlinType): IrExpression? {
|
||||
val typeObject = typeOf(type) ?: return null
|
||||
return sizeOf(typeObject)
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.alignOf(typeObject: IrExpression): IrExpression {
|
||||
val alignProperty = typeObject.type.findOverride(interop.variableTypeAlign)
|
||||
return irGet(typeObject, alignProperty)
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.alignOf(type: KotlinType): IrExpression? {
|
||||
val typeObject = typeOf(type) ?: return null
|
||||
return alignOf(typeObject)
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.arrayGet(array: IrExpression, index: IrExpression): IrExpression? {
|
||||
val elementSize = sizeOf(array.type.arguments.single().type) ?: return null
|
||||
|
||||
val offset = times(elementSize, index)
|
||||
|
||||
return irCall(interop.memberAt).apply {
|
||||
extensionReceiver = array
|
||||
putValueArgument(0, offset)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.times(left: IrExpression, right: IrExpression): IrCall {
|
||||
val times = left.type.memberScope.getSingleContributedFunction("times") {
|
||||
right.type.isSubtypeOf(it.valueParameters.single().type)
|
||||
}
|
||||
|
||||
return irCall(times).apply {
|
||||
dispatchReceiver = left
|
||||
putValueArgument(0, right)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.alloc(placement: IrExpression, size: IrExpression, align: IrExpression): IrExpression {
|
||||
val alloc = placement.type.memberScope.getSingleContributedFunction("alloc") {
|
||||
size.type.isSubtypeOf(it.valueParameters[0]!!.type) &&
|
||||
align.type.isSubtypeOf(it.valueParameters[1]!!.type)
|
||||
}
|
||||
|
||||
return irCall(alloc).apply {
|
||||
dispatchReceiver = placement
|
||||
putValueArgument(0, size)
|
||||
putValueArgument(1, align)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.allocArray(placement: IrExpression,
|
||||
elementType: KotlinType,
|
||||
length: IrExpression
|
||||
): IrExpression? {
|
||||
|
||||
val elementSize = sizeOf(elementType) ?: return null
|
||||
val size = times(elementSize, length)
|
||||
val align = alignOf(elementType) ?: return null
|
||||
|
||||
return alloc(placement, size, align)
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.alloc(placement: IrExpression, type: KotlinType): IrExpression? {
|
||||
val size = sizeOf(type) ?: return null
|
||||
val align = alignOf(type) ?: return null
|
||||
|
||||
return alloc(placement, size, align)
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
|
||||
expression.transformChildrenVoid(this)
|
||||
builder.at(expression)
|
||||
val descriptor = expression.descriptor.original
|
||||
|
||||
if (descriptor is ClassConstructorDescriptor) {
|
||||
val type = descriptor.constructedClass.defaultType
|
||||
if (type.isRepresentedAs(ValueType.C_POINTER) || type.isRepresentedAs(ValueType.NATIVE_POINTED)) {
|
||||
return expression.getValueArgument(0)!!
|
||||
}
|
||||
}
|
||||
|
||||
if (descriptor == interop.nativePointedRawPtrGetter ||
|
||||
OverridingUtil.overrides(descriptor, interop.nativePointedRawPtrGetter)) {
|
||||
|
||||
return expression.dispatchReceiver!!
|
||||
}
|
||||
|
||||
return when (descriptor) {
|
||||
interop.cPointerRawValue.getter -> expression.dispatchReceiver!!
|
||||
|
||||
interop.interpretPointed -> expression.getValueArgument(0)!!
|
||||
|
||||
interop.arrayGetByIntIndex, interop.arrayGetByLongIndex -> {
|
||||
val array = expression.extensionReceiver!!
|
||||
val index = expression.getValueArgument(0)!!
|
||||
builder.arrayGet(array, index) ?: expression
|
||||
}
|
||||
|
||||
interop.allocUninitializedArrayWithIntLength, interop.allocUninitializedArrayWithLongLength -> {
|
||||
val placement = expression.extensionReceiver!!
|
||||
val elementType = expression.type.arguments.single().type
|
||||
val length = expression.getValueArgument(0)!!
|
||||
builder.allocArray(placement, elementType, length) ?: expression
|
||||
}
|
||||
|
||||
interop.allocVariable -> {
|
||||
val placement = expression.extensionReceiver!!
|
||||
val type = expression.getSingleTypeArgument()
|
||||
builder.alloc(placement, type) ?: expression
|
||||
}
|
||||
|
||||
interop.typeOf -> {
|
||||
val type = expression.getSingleTypeArgument()
|
||||
builder.typeOf(type) ?: expression
|
||||
}
|
||||
|
||||
else -> expression
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrCall.getSingleTypeArgument(): KotlinType {
|
||||
val typeParameter = descriptor.original.typeParameters.single()
|
||||
return getTypeArgument(typeParameter)!!
|
||||
}
|
||||
}
|
||||
+9
@@ -20,3 +20,12 @@ fun nTabs(amount: Int): String {
|
||||
return String.format("%1$-${(amount+1)*4}s", "")
|
||||
}
|
||||
|
||||
fun <T> Collection<T>.atMostOne(): T? {
|
||||
return when (this.size) {
|
||||
0 -> null
|
||||
1 -> this.iterator().next()
|
||||
else -> throw IllegalArgumentException("Collection has more than one element.")
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T> Iterable<T>.atMostOne(predicate: (T) -> Boolean): T? = this.filter(predicate).atMostOne()
|
||||
@@ -1,6 +1,8 @@
|
||||
import groovy.json.JsonOutput
|
||||
import org.jetbrains.kotlin.*
|
||||
|
||||
apply plugin: NativeInteropPlugin
|
||||
|
||||
configurations {
|
||||
cli_bc
|
||||
}
|
||||
@@ -357,11 +359,46 @@ task innerClass_generic(type: RunKonanTest) {
|
||||
source = "codegen/innerClass/generic.kt"
|
||||
}
|
||||
|
||||
task innerClass_doubleInner(type: RunKonanTest) {
|
||||
goldValue = "OK\n"
|
||||
source = "codegen/innerClass/doubleInner.kt"
|
||||
}
|
||||
|
||||
task innerClass_qualifiedThis(type: RunKonanTest) {
|
||||
goldValue = "OK\n"
|
||||
source = "codegen/innerClass/qualifiedThis.kt"
|
||||
}
|
||||
|
||||
task innerClass_superOuter(type: RunKonanTest) {
|
||||
goldValue = "OK\n"
|
||||
source = "codegen/innerClass/superOuter.kt"
|
||||
}
|
||||
|
||||
task localClass_localHierarchy(type: RunKonanTest) {
|
||||
goldValue = "OK\n"
|
||||
source = "codegen/localClass/localHierarchy.kt"
|
||||
}
|
||||
|
||||
task localClass_objectExpressionInProperty(type: RunKonanTest) {
|
||||
goldValue = "OK\n"
|
||||
source = "codegen/localClass/objectExpressionInProperty.kt"
|
||||
}
|
||||
|
||||
task localClass_objectExpressionInInitializer(type: RunKonanTest) {
|
||||
goldValue = "OK\n"
|
||||
source = "codegen/localClass/objectExpressionInInitializer.kt"
|
||||
}
|
||||
|
||||
task localClass_innerWithCapture(type: RunKonanTest) {
|
||||
goldValue = "OK\n"
|
||||
source = "codegen/localClass/innerWithCapture.kt"
|
||||
}
|
||||
|
||||
task localClass_innerTakesCapturedFromOuter(type: RunKonanTest) {
|
||||
goldValue = "0\n1\n"
|
||||
source = "codegen/localClass/innerTakesCapturedFromOuter.kt"
|
||||
}
|
||||
|
||||
task array0(type: RunKonanTest) {
|
||||
goldValue = "5\n6\n7\n8\n9\n10\n11\n12\n13\n"
|
||||
source = "runtime/collections/array0.kt"
|
||||
@@ -1023,10 +1060,6 @@ task inline9(type: RunKonanTest) {
|
||||
source = "codegen/inline/inline9.kt"
|
||||
}
|
||||
|
||||
task vararg0(type: RunKonanTest) {
|
||||
source = "lower/vararg.kt"
|
||||
}
|
||||
|
||||
task inline6(type: RunKonanTest) {
|
||||
goldValue = "hello1\nhello2\nhello3\nhello4\n"
|
||||
source = "codegen/inline/inline6.kt"
|
||||
@@ -1041,3 +1074,17 @@ task inline8(type: RunKonanTest) {
|
||||
goldValue = "8\n"
|
||||
source = "codegen/inline/inline8.kt"
|
||||
}
|
||||
|
||||
kotlinNativeInterop {
|
||||
sysstat {
|
||||
pkg 'sysstat'
|
||||
headers 'sys/stat.h'
|
||||
target 'native'
|
||||
}
|
||||
}
|
||||
|
||||
task interop0(type: RunInteropKonanTest) {
|
||||
goldValue = "0\n0\n"
|
||||
source = "interop/basics/0.kt"
|
||||
interop = 'sysstat'
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
open class Father(val param: String) {
|
||||
abstract inner class InClass {
|
||||
fun work(): String {
|
||||
return param
|
||||
}
|
||||
}
|
||||
|
||||
inner class Child(p: String) : Father(p) {
|
||||
inner class Child2 : Father.InClass {
|
||||
constructor(): super()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return Father("fail").Child("OK").Child2().work()
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(box())
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
open class Outer(val outer: String) {
|
||||
open inner class Inner(val inner: String): Outer(inner) {
|
||||
fun foo() = outer
|
||||
}
|
||||
|
||||
fun value() = Inner("OK").foo()
|
||||
}
|
||||
|
||||
fun box() = Outer("Fail").value()
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
println(box())
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fun box() {
|
||||
var previous: Any? = null
|
||||
for (i in 0 .. 2) {
|
||||
class Outer {
|
||||
inner class Inner {
|
||||
override fun toString() = i.toString()
|
||||
}
|
||||
|
||||
override fun toString() = Inner().toString()
|
||||
}
|
||||
if (previous != null) println(previous.toString())
|
||||
previous = Outer()
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
box()
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fun box(s: String): String {
|
||||
class Local {
|
||||
open inner class Inner() {
|
||||
open fun result() = s
|
||||
}
|
||||
}
|
||||
|
||||
return Local().Inner().result()
|
||||
}
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
println(box("OK"))
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
fun foo(s: String): String {
|
||||
open class Local {
|
||||
fun f() = s
|
||||
}
|
||||
|
||||
open class Derived: Local() {
|
||||
fun g() = f()
|
||||
}
|
||||
|
||||
return Derived().g()
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(foo("OK"))
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
abstract class Father {
|
||||
abstract inner class InClass {
|
||||
abstract fun work(): String
|
||||
}
|
||||
}
|
||||
|
||||
class Child : Father() {
|
||||
val ChildInClass : InClass
|
||||
|
||||
init {
|
||||
ChildInClass = object : Father.InClass() {
|
||||
override fun work(): String {
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return Child().ChildInClass.work()
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(box())
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
abstract class Father {
|
||||
abstract inner class InClass {
|
||||
abstract fun work(): String
|
||||
}
|
||||
}
|
||||
|
||||
class Child : Father() {
|
||||
val ChildInClass = object : Father.InClass() {
|
||||
override fun work(): String {
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return Child().ChildInClass.work()
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(box())
|
||||
}
|
||||
backend.native/tests/external/codegen/blackbox/innerNested/superConstructorCall/innerExtendsOuter.kt
Vendored
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
open class Outer(vararg val chars: Char) {
|
||||
open inner class Inner(val s: String): Outer(s[0], s[1]) {
|
||||
fun concat() = java.lang.String.valueOf(chars)
|
||||
fun concat() = fromCharArrays(chars, 0, chars.size)
|
||||
}
|
||||
|
||||
fun value() = Inner("OK").concat()
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import sysstat.*
|
||||
import kotlinx.cinterop.*
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val statBuf = nativeHeap.alloc<statStruct>()
|
||||
val res = stat("/", statBuf.ptr)
|
||||
println(res)
|
||||
println(statBuf.st_uid.value)
|
||||
}
|
||||
Reference in New Issue
Block a user