Merge branch 'master' into inline

This commit is contained in:
KonstantinAnisimov
2017-01-20 10:26:34 +07:00
committed by GitHub
62 changed files with 1491 additions and 1404 deletions
@@ -1,27 +0,0 @@
/*
* 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
import org.jetbrains.kotlin.backend.common.descriptors.SharedVariablesManager
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
interface BackendContext {
val builtIns: KotlinBuiltIns
val irBuiltIns: IrBuiltIns
val sharedVariablesManager: SharedVariablesManager
}
@@ -1,97 +0,0 @@
/*
* 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
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
interface FileLoweringPass {
fun lower(irFile: IrFile)
}
interface ClassLoweringPass {
fun lower(irClass: IrClass)
}
interface DeclarationContainerLoweringPass {
fun lower(irDeclarationContainer: IrDeclarationContainer)
}
interface FunctionLoweringPass {
fun lower(irFunction: IrFunction)
}
interface BodyLoweringPass {
fun lower(irBody: IrBody)
}
fun ClassLoweringPass.runOnFilePostfix(irFile: IrFile) {
irFile.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitClass(declaration: IrClass) {
declaration.acceptChildrenVoid(this)
lower(declaration)
}
})
}
fun DeclarationContainerLoweringPass.asClassLoweringPass() = object : ClassLoweringPass {
override fun lower(irClass: IrClass) {
this@asClassLoweringPass.lower(irClass)
}
}
fun DeclarationContainerLoweringPass.runOnFilePostfix(irFile: IrFile) {
this.asClassLoweringPass().runOnFilePostfix(irFile)
this.lower(irFile)
}
fun BodyLoweringPass.runOnFilePostfix(irFile: IrFile) {
irFile.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitBody(body: IrBody) {
body.acceptChildrenVoid(this)
lower(body)
}
})
}
fun FunctionLoweringPass.runOnFilePostfix(irFile: IrFile) {
irFile.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitFunction(declaration: IrFunction) {
declaration.acceptChildrenVoid(this)
lower(declaration)
}
})
}
@@ -1,31 +0,0 @@
/*
* 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.descriptors
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.IrSetVariable
interface SharedVariablesManager {
fun createSharedVariableDescriptor(variableDescriptor: VariableDescriptor): VariableDescriptor
fun defineSharedValue(sharedVariableDescriptor: VariableDescriptor, originalDeclaration: IrVariable): IrStatement
fun getSharedValue(sharedVariableDescriptor: VariableDescriptor, originalGet: IrGetValue): IrExpression
fun setSharedValue(sharedVariableDescriptor: VariableDescriptor, originalSet: IrSetVariable): IrExpression
}
@@ -1,371 +0,0 @@
/*
* 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.lower
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.descriptors.*
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.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer
import org.jetbrains.kotlin.ir.declarations.IrFunction
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.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.parents
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
import org.jetbrains.kotlin.types.KotlinType
import java.util.*
class LocalFunctionsLowering(val context: BackendContext): DeclarationContainerLoweringPass {
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.declarations.transformFlat { memberDeclaration ->
if (memberDeclaration is IrFunction)
LocalFunctionsTransformer(memberDeclaration).lowerLocalFunctions()
else
null
}
}
private class LocalFunctionContext(val declaration: IrFunction) {
lateinit var closure: Closure
val closureParametersCount: Int get() = closure.capturedValues.size
lateinit var transformedDescriptor: FunctionDescriptor
val old2new: MutableMap<ValueDescriptor, ValueDescriptor> = HashMap()
var index: Int = -1
override fun toString(): String =
"LocalFunctionContext for ${declaration.descriptor}"
}
private inner class LocalFunctionsTransformer(val memberFunction: IrFunction) {
val localFunctions: MutableMap<FunctionDescriptor, LocalFunctionContext> = LinkedHashMap()
val new2old: MutableMap<ValueDescriptor, ValueDescriptor> = HashMap()
fun lowerLocalFunctions(): List<IrDeclaration>? {
collectLocalFunctions()
if (localFunctions.isEmpty()) return null
collectClosures()
transformDescriptors()
rewriteBodies()
return collectRewrittenDeclarations()
}
private fun collectRewrittenDeclarations(): ArrayList<IrDeclaration> =
ArrayList<IrDeclaration>(localFunctions.size + 1).apply {
add(memberFunction)
localFunctions.values.mapTo(this) {
val original = it.declaration
IrFunctionImpl(
original.startOffset, original.endOffset, original.origin,
it.transformedDescriptor,
original.body
)
}
}
private inner class FunctionBodiesRewriter(val localFunctionContext: LocalFunctionContext?) : IrElementTransformerVoid() {
override fun visitClass(declaration: IrClass): IrStatement {
// ignore local classes for now
return declaration
}
override fun visitFunction(declaration: IrFunction): IrStatement {
// replace local function definition with an empty composite
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
}
override fun visitGetValue(expression: IrGetValue): IrExpression {
val remapped = localFunctionContext?.let { it.old2new[expression.descriptor] }
return if (remapped == null)
expression
else
IrGetValueImpl(expression.startOffset, expression.endOffset, remapped, expression.origin)
}
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
val oldCallee = expression.descriptor.original
val localFunctionData = localFunctions[oldCallee] ?: return expression
val newCallee = localFunctionData.transformedDescriptor
val newCall = createNewCall(expression, newCallee).fillArguments(localFunctionData, expression)
return newCall
}
private fun <T : IrMemberAccessExpression> T.fillArguments(calleeContext: LocalFunctionContext, oldExpression: IrMemberAccessExpression): T {
val closureParametersCount = calleeContext.closureParametersCount
mapValueParametersIndexed { index, newValueParameterDescriptor ->
val capturedValueDescriptor = new2old[newValueParameterDescriptor] ?:
throw AssertionError("Non-mapped parameter $newValueParameterDescriptor")
if (index >= closureParametersCount)
oldExpression.getValueArgument(capturedValueDescriptor as ValueParameterDescriptor)
else {
val remappedValueDescriptor = localFunctionContext?.let { it.old2new[capturedValueDescriptor] }
IrGetValueImpl(oldExpression.startOffset, oldExpression.endOffset,
remappedValueDescriptor ?: capturedValueDescriptor)
}
}
dispatchReceiver = oldExpression.dispatchReceiver
extensionReceiver = oldExpression.extensionReceiver
return this
}
override fun visitCallableReference(expression: IrCallableReference): IrExpression {
expression.transformChildrenVoid(this)
val oldCallee = expression.descriptor.original
val localFunctionData = localFunctions[oldCallee] ?: return expression
val newCallee = localFunctionData.transformedDescriptor
val newCallableReference = IrCallableReferenceImpl(
expression.startOffset, expression.endOffset,
expression.type, // TODO functional type for transformed descriptor
newCallee,
remapTypeArguments(expression, newCallee),
expression.origin
).fillArguments(localFunctionData, expression)
return newCallableReference
}
override fun visitReturn(expression: IrReturn): IrExpression {
expression.transformChildrenVoid(this)
val oldReturnTarget = expression.returnTarget
val localFunctionData = localFunctions[oldReturnTarget] ?: return expression
val newReturnTarget = localFunctionData.transformedDescriptor
return IrReturnImpl(expression.startOffset, expression.endOffset, newReturnTarget, expression.value)
}
}
private fun rewriteFunctionDeclaration(irFunction: IrFunction, localFunctionContext: LocalFunctionContext?) {
irFunction.transformChildrenVoid(FunctionBodiesRewriter(localFunctionContext))
}
private fun rewriteBodies() {
localFunctions.values.forEach {
rewriteFunctionDeclaration(it.declaration, it)
}
rewriteFunctionDeclaration(memberFunction, null)
}
private fun createNewCall(oldCall: IrCall, newCallee: FunctionDescriptor) =
if (oldCall is IrCallWithShallowCopy)
oldCall.shallowCopy(oldCall.origin, newCallee, oldCall.superQualifier)
else
IrCallImpl(
oldCall.startOffset, oldCall.endOffset,
newCallee,
remapTypeArguments(oldCall, newCallee),
oldCall.origin, oldCall.superQualifier
)
private fun remapTypeArguments(oldExpression: IrMemberAccessExpression, newCallee: FunctionDescriptor): Map<TypeParameterDescriptor, KotlinType>? {
val oldCallee = oldExpression.descriptor
return if (oldCallee.typeParameters.isEmpty())
null
else oldCallee.typeParameters.associateBy(
{ newCallee.typeParameters[it.index] },
{ oldExpression.getTypeArgument(it)!! }
)
}
private fun transformDescriptors() {
localFunctions.values.forEach {
it.transformedDescriptor = createTransformedDescriptor(it)
}
}
private fun suggestLocalName(descriptor: DeclarationDescriptor): String {
val localFunctionContext = localFunctions[descriptor]
return if (localFunctionContext != null && localFunctionContext.index >= 0)
"lambda-${localFunctionContext.index}"
else
descriptor.name.asString()
}
private fun generateNameForLiftedFunction(functionDescriptor: FunctionDescriptor): Name =
Name.identifier(
functionDescriptor.parentsWithSelf
.takeWhile { it is FunctionDescriptor }
.toList().reversed()
.map { suggestLocalName(it) }
.joinToString(separator = "$")
)
private fun createTransformedDescriptor(localFunctionContext: LocalFunctionContext): FunctionDescriptor {
val oldDescriptor = localFunctionContext.declaration.descriptor
val memberOwner = memberFunction.descriptor.containingDeclaration
val newDescriptor = SimpleFunctionDescriptorImpl.create(
memberOwner,
oldDescriptor.annotations,
generateNameForLiftedFunction(oldDescriptor),
CallableMemberDescriptor.Kind.SYNTHESIZED,
oldDescriptor.source
)
val closureParametersCount = localFunctionContext.closureParametersCount
val newValueParametersCount = closureParametersCount + oldDescriptor.valueParameters.size
val newDispatchReceiverParameter =
if (memberOwner is ClassDescriptor && oldDescriptor.dispatchReceiverParameter != null)
memberOwner.thisAsReceiverParameter
else
null
// Do not substitute type parameters for now.
val newTypeParameters = oldDescriptor.typeParameters
val newValueParameters = ArrayList<ValueParameterDescriptor>(newValueParametersCount).apply {
localFunctionContext.closure.capturedValues.mapIndexedTo(this) { i, capturedValueDescriptor ->
createUnsubstitutedCapturedValueParameter(newDescriptor, capturedValueDescriptor, i).apply {
localFunctionContext.recordRemapped(capturedValueDescriptor, this)
}
}
oldDescriptor.valueParameters.mapIndexedTo(this) { i, oldValueParameterDescriptor ->
createUnsubstitutedParameter(newDescriptor, oldValueParameterDescriptor, closureParametersCount + i).apply {
localFunctionContext.recordRemapped(oldValueParameterDescriptor, this)
}
}
}
newDescriptor.initialize(
oldDescriptor.extensionReceiverParameter?.type,
newDispatchReceiverParameter,
newTypeParameters,
newValueParameters,
oldDescriptor.returnType,
Modality.FINAL,
Visibilities.PRIVATE
)
oldDescriptor.extensionReceiverParameter?.let {
localFunctionContext.recordRemapped(it, newDescriptor.extensionReceiverParameter!!)
}
return newDescriptor
}
private fun LocalFunctionContext.recordRemapped(oldDescriptor: ValueDescriptor, newDescriptor: ValueDescriptor): ValueDescriptor {
old2new[oldDescriptor] = newDescriptor
new2old[newDescriptor] = oldDescriptor
return newDescriptor
}
private fun suggestNameForCapturedValueParameter(valueDescriptor: ValueDescriptor): Name =
if (valueDescriptor.name.isSpecial) {
val oldNameStr = valueDescriptor.name.asString()
Name.identifier("$" + oldNameStr.substring(1, oldNameStr.length - 1))
}
else
valueDescriptor.name
private fun createUnsubstitutedCapturedValueParameter(
newParameterOwner: CallableMemberDescriptor,
valueDescriptor: ValueDescriptor,
index: Int
): ValueParameterDescriptor =
ValueParameterDescriptorImpl(
newParameterOwner, null, index,
valueDescriptor.annotations,
suggestNameForCapturedValueParameter(valueDescriptor),
valueDescriptor.type,
false, false, false, null, valueDescriptor.source
)
private fun createUnsubstitutedParameter(
newParameterOwner: CallableMemberDescriptor,
valueParameterDescriptor: ValueParameterDescriptor,
newIndex: Int
): ValueParameterDescriptor =
valueParameterDescriptor.copy(newParameterOwner, valueParameterDescriptor.name, newIndex)
private fun collectClosures() {
memberFunction.acceptChildrenVoid(object : AbstractClosureAnnotator() {
override fun visitClass(declaration: IrClass) {
// ignore local classes for now
return
}
override fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure) {
localFunctions[functionDescriptor]?.closure = closure
}
override fun recordClassClosure(classDescriptor: ClassDescriptor, closure: Closure) {
// ignore local classes for now
}
})
}
private fun collectLocalFunctions() {
memberFunction.acceptChildrenVoid(object : IrElementVisitorVoid {
var lambdasCount = 0
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitFunction(declaration: IrFunction) {
declaration.acceptChildrenVoid(this)
val localFunctionContext = LocalFunctionContext(declaration)
localFunctions[declaration.descriptor] = localFunctionContext
if (declaration.descriptor.name.isSpecial) {
localFunctionContext.index = lambdasCount++
}
}
override fun visitClass(declaration: IrClass) {
// ignore local classes for now
}
})
}
}
}
@@ -5,16 +5,13 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.types.KotlinType
class IrLoweringContext(backendContext: BackendContext) : GeneratorContext {
override val irBuiltIns: IrBuiltIns = backendContext.irBuiltIns
}
class IrLoweringContext(backendContext: BackendContext) : IrGeneratorContext(backendContext.irBuiltIns)
class FunctionIrGenerator(backendContext: BackendContext, functionDescriptor: FunctionDescriptor) : GeneratorWithScope {
class FunctionIrGenerator(backendContext: BackendContext, functionDescriptor: FunctionDescriptor) : IrGeneratorWithScope {
override val context = IrLoweringContext(backendContext)
override val scope = Scope(functionDescriptor)
}
@@ -1,133 +0,0 @@
/*
* 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.lower
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.IrSetVariable
import org.jetbrains.kotlin.ir.expressions.IrValueAccessExpression
import org.jetbrains.kotlin.ir.visitors.*
import java.util.*
class SharedVariablesLowering(val context: BackendContext) : FunctionLoweringPass {
override fun lower(irFunction: IrFunction) {
SharedVariablesTransformer(irFunction).lowerSharedVariables()
}
private inner class SharedVariablesTransformer(val irFunction: IrFunction) {
val sharedVariables = HashSet<ValueDescriptor>()
fun lowerSharedVariables() {
collectSharedVariables()
if (sharedVariables.isEmpty()) return
rewriteSharedVariables()
}
private fun collectSharedVariables() {
irFunction.acceptVoid(object : IrElementVisitorVoid {
val declarationsStack = ArrayDeque<IrDeclaration>()
val currentDeclaration: DeclarationDescriptor
get() = declarationsStack.peek().descriptor
val relevantVars = HashSet<VariableDescriptor>()
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitFunction(declaration: IrFunction) {
declarationsStack.push(declaration)
declaration.acceptChildrenVoid(this)
declarationsStack.pop()
}
override fun visitVariable(declaration: IrVariable) {
declaration.acceptChildrenVoid(this)
val variableDescriptor = declaration.descriptor
if (variableDescriptor.isVar) {
relevantVars.add(variableDescriptor)
}
}
override fun visitVariableAccess(expression: IrValueAccessExpression) {
expression.acceptChildrenVoid(this)
val descriptor = expression.descriptor
if (descriptor in relevantVars && descriptor.containingDeclaration != currentDeclaration) {
sharedVariables.add(descriptor)
}
}
})
}
private fun rewriteSharedVariables() {
val transformedDescriptors = HashMap<ValueDescriptor, VariableDescriptor>()
irFunction.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitVariable(declaration: IrVariable): IrStatement {
declaration.transformChildrenVoid(this)
val oldDescriptor = declaration.descriptor
if (oldDescriptor !in sharedVariables) return declaration
val newDescriptor = context.sharedVariablesManager.createSharedVariableDescriptor(oldDescriptor)
transformedDescriptors[oldDescriptor] = newDescriptor
return context.sharedVariablesManager.defineSharedValue(newDescriptor, declaration)
}
})
irFunction.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid(this)
val newDescriptor = getTransformedDescriptor(expression.descriptor) ?: return expression
return context.sharedVariablesManager.getSharedValue(newDescriptor, expression)
}
override fun visitSetVariable(expression: IrSetVariable): IrExpression {
expression.transformChildrenVoid(this)
val newDescriptor = getTransformedDescriptor(expression.descriptor) ?: return expression
return context.sharedVariablesManager.setSharedValue(newDescriptor, expression)
}
private fun getTransformedDescriptor(oldDescriptor: ValueDescriptor): VariableDescriptor? =
transformedDescriptors.getOrElse(oldDescriptor) {
assert(oldDescriptor !in sharedVariables) {
"Shared variable is not transformed: $oldDescriptor"
}
null
}
})
}
}
}
@@ -17,6 +17,10 @@ internal class KonanLower(val context: Context) {
fun lower(irFile: IrFile) {
val phaser = PhaseManager(context)
phaser.phase(KonanPhase.LOWER_DEFAULT_PARAMETER_EXTENT) {
DefaultParameterStubGenerator(context).runOnFilePostfix(irFile)
DefaultParameterInjector(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.LOWER_BUILTIN_OPERATORS) {
BuiltinOperatorLowering(context).runOnFilePostfix(irFile)
}
@@ -11,6 +11,7 @@ enum class KonanPhase(val description: String,
/* */ BACKEND("All backend"),
/* ... */ LOWER("IR Lowering"),
/* ... ... */ LOWER_BUILTIN_OPERATORS("BuiltIn Operators Lowering"),
/* ... ... */ LOWER_DEFAULT_PARAMETER_EXTENT("Default Parameter Extent Lowering"),
/* ... ... */ LOWER_TYPE_OPERATORS("Type operators lowering"),
/* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering"),
/* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering"),
@@ -18,8 +18,8 @@ package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.backend.konan.KonanPlatformConfigurator
import org.jetbrains.kotlin.descriptors.PlatformKind
import org.jetbrains.kotlin.resolve.ImportPath
import org.jetbrains.kotlin.resolve.MultiTargetPlatform
import org.jetbrains.kotlin.resolve.PlatformConfigurator
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.storage.StorageManager
@@ -35,7 +35,7 @@ class KonanBuiltIns: KotlinBuiltIns {
}
object KonanPlatform : TargetPlatform("Konan") {
override val kind = PlatformKind.DEFAULT /* TODO: native */
override val multiTargetPlatform = MultiTargetPlatform.Specific(platformName)
override val defaultImports: List<ImportPath> = Default.defaultImports + listOf(
ImportPath("kotlin.*"),
ImportPath("kotlin.collections.*"),
@@ -33,7 +33,7 @@ internal class MacOSPlatform(distrib: Distribution,
override val linkerOptimizationFlags =
properties.propertyList("linkerOptimizationFlags.osx")
override val linkerKonanFlags = listOf(distrib.libCppAbi)
override val linkerKonanFlags = properties.propertyList("linkerKonanFlags.osx")
override val linker = "${distrib.sysRoot}/usr/bin/ld"
override fun linkCommand(objectFiles: List<String>, executable: String, optimize: Boolean): List<String> {
@@ -31,7 +31,8 @@ import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProvid
object TopDownAnalyzerFacadeForKonan {
fun analyzeFiles(files: Collection<KtFile>, config: KonanConfig): AnalysisResult {
val context = ContextForNewModule(ProjectContext(config.project), Name.special("<${config.moduleId}>"), KonanPlatform.builtIns)
val context = ContextForNewModule(ProjectContext(config.project), Name.special("<${config.moduleId}>"),
KonanPlatform.builtIns, null)
val builtinsForCompilerModule = KonanBuiltIns(context.storageManager, true)
val compilerBuiltInsModule = builtinsForCompilerModule.builtInsModule
@@ -1,6 +1,8 @@
package org.jetbrains.kotlin.backend.konan.descriptors
import org.jetbrains.kotlin.backend.konan.KonanBuiltIns
import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
@@ -103,7 +105,7 @@ internal fun KonanBuiltIns.getKonanInternalClassOrNull(name: String): ClassDescr
* @return built-in class `konan.internal.$name`
*/
internal fun KonanBuiltIns.getKonanInternalClass(name: String): ClassDescriptor =
getKonanInternalClassOrNull(name)!!
getKonanInternalClassOrNull(name) ?: TODO(name)
internal fun KonanBuiltIns.getKonanInternalFunctions(name: String): List<FunctionDescriptor> {
return konanInternal.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).toList()
@@ -149,3 +151,61 @@ internal val FunctionDescriptor.isFunctionInvoke: Boolean
}
internal fun ClassDescriptor.isUnit() = this.defaultType.isUnit()
internal val ClassDescriptor.сontributedMethods: List<FunctionDescriptor>
get() {
val contributedDescriptors = unsubstitutedMemberScope.getContributedDescriptors()
// (includes declarations from supers)
val functions = contributedDescriptors.filterIsInstance<FunctionDescriptor>()
val properties = contributedDescriptors.filterIsInstance<PropertyDescriptor>()
val getters = properties.mapNotNull { it.getter }
val setters = properties.mapNotNull { it.setter }
val allMethods = (functions + getters + setters).sortedBy {
// TODO: use local hash instead, but it needs major refactoring.
it.functionName.hashCode()
}
return allMethods
}
fun ClassDescriptor.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT
// TODO: optimize
val ClassDescriptor.vtableEntries: List<FunctionDescriptor>
get() {
assert(!this.isInterface)
val superVtableEntries = if (KotlinBuiltIns.isSpecialClassWithNoSupertypes(this)) {
emptyList()
} else {
this.getSuperClassOrAny().vtableEntries
}
val methods = this.сontributedMethods
val inheritedVtableSlots = superVtableEntries.map { superMethod ->
methods.single { OverridingUtil.overrides(it, superMethod) }
}
return inheritedVtableSlots + (methods - inheritedVtableSlots).filter { it.isOverridable }
}
val ClassDescriptor.vtableSize: Int
get() = if (this.isAbstract()) 0 else this.vtableEntries.size
fun ClassDescriptor.vtableIndex(function: FunctionDescriptor): Int {
this.vtableEntries.forEachIndexed { index, functionDescriptor ->
if (functionDescriptor == function.original) return index
}
throw Error(function.toString() + " not in vtable of " + this.toString())
}
val ClassDescriptor.methodTableEntries: List<FunctionDescriptor>
get() {
assert (!this.isAbstract())
return this.сontributedMethods.filter { it.isOverridableOrOverrides }
// TODO: probably method table should contain all accessible methods to improve binary compatibility
}
@@ -7,6 +7,7 @@ import org.jetbrains.kotlin.backend.konan.Distribution
import org.jetbrains.kotlin.backend.konan.hash.GlobalHash
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
import org.jetbrains.kotlin.backend.konan.descriptors.backingField
import org.jetbrains.kotlin.backend.konan.descriptors.vtableSize
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
@@ -114,22 +115,24 @@ internal interface ContextUtils {
return constValue(result)
}
/**
* Pointer to struct { TypeInfo, vtable }.
*/
val ClassDescriptor.typeInfoWithVtable: ConstPointer
get() {
val type = structType(runtime.typeInfoType, LLVMArrayType(int8TypePtr, this.vtableSize)!!)
return constPointer(externalGlobal(this.typeInfoSymbolName, type))
}
val ClassDescriptor.typeInfoPtr: ConstPointer
get() = typeInfoWithVtable.getElementPtr(0)
/**
* Pointer to type info for given class.
* It may be declared as pointer to external variable.
*/
val ClassDescriptor.llvmTypeInfoPtr: LLVMValueRef
get() {
val module = context.llvmModule
val globalName = this.typeInfoSymbolName
val globalPtr = LLVMGetNamedGlobal(module, globalName) ?:
LLVMAddGlobal(module, runtime.typeInfoType, globalName)!!
return globalPtr
}
val ClassDescriptor.typeInfoPtr: ConstPointer
get() = constPointer(this.llvmTypeInfoPtr)
get() = typeInfoPtr.llvm
/**
* Pointer to type info for this type, or `null` if the type doesn't have corresponding type info.
@@ -1337,11 +1337,12 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
private fun evaluateGetField(value: IrGetField): LLVMValueRef {
context.log("evaluateGetField : ${ir2string(value)}")
if (value.descriptor.dispatchReceiverParameter != null) {
val thisPtr = instanceFieldAccessReceiver(value)
val thisPtr = evaluateExpression(value.receiver!!)
return codegen.loadSlot(
fieldPtrOfClass(thisPtr, value.descriptor), value.descriptor.isVar())
}
else {
assert (value.receiver == null)
val ptr = LLVMGetNamedGlobal(context.llvmModule, value.descriptor.symbolName)!!
return codegen.loadSlot(ptr, value.descriptor.isVar())
}
@@ -1362,26 +1363,15 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
private fun instanceFieldAccessReceiver(expression: IrFieldAccessExpression): LLVMValueRef {
val receiverExpression = expression.receiver
if (receiverExpression != null) {
return evaluateExpression(receiverExpression)
} else {
val classDescriptor = expression.descriptor.containingDeclaration as ClassDescriptor
return currentCodeContext.genGetValue(classDescriptor.thisAsReceiverParameter)
}
}
//-------------------------------------------------------------------------//
private fun evaluateSetField(value: IrSetField): LLVMValueRef {
context.log("evaluateSetField : ${ir2string(value)}")
val valueToAssign = evaluateExpression(value.value)
if (value.descriptor.dispatchReceiverParameter != null) {
val thisPtr = instanceFieldAccessReceiver(value)
val thisPtr = evaluateExpression(value.receiver!!)
codegen.storeAnyGlobal(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor))
}
else {
assert (value.receiver == null)
val globalValue = LLVMGetNamedGlobal(context.llvmModule, value.descriptor.symbolName)
codegen.storeAnyGlobal(valueToAssign, globalValue!!)
}
@@ -1741,7 +1731,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
val typeInfo = codegen.typeInfoValue(containingClass)
val allocHint = Int32(1).llvm
val thisValue = if (containingClass.isArray) {
assert(args.size == 1 && args[0].type == int32Type)
assert(args.size >= 1 && args[0].type == int32Type)
val allocArrayInstanceArgs = listOf(typeInfo, allocHint, args[0])
call(context.llvm.allocArrayFunction, allocArrayInstanceArgs)
} else {
@@ -1854,14 +1844,30 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
fun callVirtual(descriptor: FunctionDescriptor, args: List<LLVMValueRef>): LLVMValueRef {
val thisI8PtrPtr = codegen.bitcast(kInt8PtrPtr, args[0]) // Cast "this (i8*)" to i8**.
val typeInfoI8Ptr = codegen.load(thisI8PtrPtr) // Load TypeInfo address.
val typeInfoPtr = codegen.bitcast(codegen.kTypeInfoPtr, typeInfoI8Ptr) // Cast TypeInfo (i8*) to TypeInfo*.
val methodHash = codegen.functionHash(descriptor) // Calculate hash of the method to be invoked
val lookupArgs = listOf(typeInfoPtr, methodHash) // Prepare args for lookup
val llvmMethod = call(context.llvm.lookupOpenMethodFunction,
lookupArgs) // Get method ptr to be invoked
val typeInfoPtrPtr = LLVMBuildStructGEP(codegen.builder, args[0], 0 /* type_info */, "")!!
val typeInfoPtr = codegen.load(typeInfoPtrPtr)
assert (typeInfoPtr.type == codegen.kTypeInfoPtr)
val owner = descriptor.containingDeclaration as ClassDescriptor
val llvmMethod = if (!owner.isInterface) {
// If this is a virtual method of the class - we can call via vtable.
val index = owner.vtableIndex(descriptor)
val vtablePlace = codegen.gep(typeInfoPtr, Int32(1).llvm) // typeInfoPtr + 1
val vtable = codegen.bitcast(kInt8PtrPtr, vtablePlace)
val slot = codegen.gep(vtable, Int32(index).llvm)
codegen.load(slot)
} else {
// Otherwise, call via hashtable.
// TODO: optimize by storing interface number in lower bits of 'this' pointer
// when passing object as an interface. This way we can use those bits as index
// for an additional per-interface vtable.
val methodHash = codegen.functionHash(descriptor) // Calculate hash of the method to be invoked
val lookupArgs = listOf(typeInfoPtr, methodHash) // Prepare args for lookup
call(context.llvm.lookupOpenMethodFunction,
lookupArgs)
}
val functionPtrType = pointerType(codegen.getLlvmFunctionType(descriptor)) // Construct type of the method to be invoked
val function = codegen.bitcast(functionPtrType, llvmMethod) // Cast method address to the type
return call(descriptor, function, args) // Invoke the method
@@ -150,8 +150,9 @@ internal fun structType(types: List<LLVMTypeRef>): LLVMTypeRef = memScoped {
}
internal fun ContextUtils.getLlvmFunctionType(function: FunctionDescriptor): LLVMTypeRef {
val returnType = if (function is ConstructorDescriptor) voidType else getLLVMReturnType(function.returnType!!)
val paramTypes = ArrayList(function.allValueParameters.map { getLLVMType(it.type) })
val original = function.original
val returnType = if (original is ConstructorDescriptor) voidType else getLLVMReturnType(original.returnType!!)
val paramTypes = ArrayList(original.allValueParameters.map { getLLVMType(it.type) })
if (isObjectType(returnType)) paramTypes.add(kObjHeaderPtrPtr)
memScoped {
@@ -1,13 +1,15 @@
package org.jetbrains.kotlin.backend.konan.llvm
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassKind.*
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.resolve.findOriginalTopMostOverriddenDescriptors
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
@@ -21,7 +23,7 @@ private val exportForCppRuntimeAnnotation = FqName("konan.internal.ExportForCppR
fun typeToHashString(type: KotlinType): String {
if (TypeUtils.isTypeParameter(type)) return "GENERIC"
var hashString = type.constructor.toString()
var hashString = TypeUtils.getClassDescriptor(type)!!.fqNameSafe.asString()
if (!type.arguments.isEmpty()) {
hashString += "<${type.arguments.map {
typeToHashString(it.type)
@@ -94,4 +96,4 @@ internal val ClassDescriptor.typeInfoSymbolName: String
get() = "ktype:" + this.fqNameSafe.toString()
internal val PropertyDescriptor.symbolName:String
get() = "kvar:${this.containingDeclaration.name.asString()}.${this.name.asString()}"
get() = "kvar:${this.containingDeclaration.name.asString()}.${this.name.asString()}"
@@ -4,16 +4,12 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.*
import llvm.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.implementation
import org.jetbrains.kotlin.backend.konan.descriptors.implementedInterfaces
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
@@ -31,7 +27,6 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
val objOffsetsCount: Int,
val interfaces: ConstValue,
val interfacesCount: Int,
val vtable: ConstValue,
val methods: ConstValue,
val methodsCount: Int,
val fields: ConstValue,
@@ -50,8 +45,6 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
interfaces,
Int32(interfacesCount),
vtable,
methods,
Int32(methodsCount),
@@ -71,46 +64,6 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
return classType
}
// TODO: optimize
private fun getVtableEntries(classDesc: ClassDescriptor): List<FunctionDescriptor> {
assert (!classDesc.isInterface)
val superVtableEntries = if (KotlinBuiltIns.isSpecialClassWithNoSupertypes(classDesc)) {
emptyList()
} else {
getVtableEntries(classDesc.getSuperClassOrAny())
}
val methods = classDesc.getContributedMethods() // TODO: ensure order is well-defined
val inheritedVtableSlots = superVtableEntries.map { superMethod ->
methods.single { OverridingUtil.overrides(it, superMethod) }
}
return inheritedVtableSlots + (methods - inheritedVtableSlots).filter { it.isOverridable }
}
private fun getMethodTableEntries(classDesc: ClassDescriptor): List<FunctionDescriptor> {
assert (classDesc.modality != Modality.ABSTRACT)
return classDesc.getContributedMethods().filter { it.isOverridableOrOverrides }
// TODO: probably method table should contain all accessible methods to improve binary compatibility
}
private fun ClassDescriptor.getContributedMethods(): List<FunctionDescriptor> {
val contributedDescriptors = unsubstitutedMemberScope.getContributedDescriptors()
// (includes declarations from supers)
val functions = contributedDescriptors.filterIsInstance<FunctionDescriptor>()
val properties = contributedDescriptors.filterIsInstance<PropertyDescriptor>()
val getters = properties.mapNotNull { it.getter }
val setters = properties.mapNotNull { it.setter }
val allMethods = functions + getters + setters
return allMethods
}
private fun exportTypeInfoIfRequired(classDesc: ClassDescriptor, typeInfoGlobal: LLVMValueRef?) {
val annot = classDesc.annotations.findAnnotation(FqName("konan.ExportTypeInfo"))
if (annot != null) {
@@ -181,26 +134,27 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
val fieldsPtr = staticData.placeGlobalConstArray("kfields:$className",
runtime.fieldTableRecordType, fields)
val vtable: List<ConstValue>
val vtableEntries: List<ConstValue>
val methods: List<ConstValue>
if (classDesc.modality != Modality.ABSTRACT) {
if (!classDesc.isAbstract()) {
// TODO: compile-time resolution limits binary compatibility
vtable = getVtableEntries(classDesc).map { it.implementation.entryPointAddress }
vtableEntries = classDesc.vtableEntries.map { it.implementation.entryPointAddress }
methods = getMethodTableEntries(classDesc).map {
methods = classDesc.methodTableEntries.map {
val nameSignature = it.functionName.localHash
// TODO: compile-time resolution limits binary compatibility
val methodEntryPoint = it.implementation.entryPointAddress
MethodTableRecord(nameSignature, methodEntryPoint)
}.sortedBy { it.nameSignature.value }
} else {
vtable = emptyList()
vtableEntries = emptyList()
methods = emptyList()
}
assert (vtableEntries.size == classDesc.vtableSize)
val vtablePtr = staticData.placeGlobalConstArray("kvtable:$className", pointerType(int8Type), vtable)
val vtable = ConstArray(int8TypePtr, vtableEntries)
val methodsPtr = staticData.placeGlobalConstArray("kmethods:$className",
runtime.methodTableRecordType, methods)
@@ -209,15 +163,14 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
superType,
objOffsetsPtr, objOffsets.size,
interfacesPtr, interfaces.size,
vtablePtr,
methodsPtr, methods.size,
fieldsPtr, if (classDesc.isInterface) -1 else fields.size)
val typeInfoGlobal = classDesc.llvmTypeInfoPtr // TODO: it is a hack
LLVMSetInitializer(typeInfoGlobal, typeInfo.llvm)
val typeInfoGlobal = classDesc.typeInfoWithVtable.llvm // TODO: it is a hack
LLVMSetInitializer(typeInfoGlobal, Struct(typeInfo, vtable).llvm)
LLVMSetGlobalConstant(typeInfoGlobal, 1)
exportTypeInfoIfRequired(classDesc, typeInfoGlobal)
exportTypeInfoIfRequired(classDesc, classDesc.llvmTypeInfoPtr)
}
}
@@ -9,9 +9,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.unboundCallableReferenceTy
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -120,27 +118,42 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
}
override fun IrExpression.useAs(type: KotlinType): IrExpression {
return this.adaptIfNecessary(type)
val actualType = when (this) {
is IrCall -> this.descriptor.original.returnType ?: this.type
is IrGetField -> this.descriptor.original.type
else -> this.type
}
return this.adaptIfNecessary(actualType, type)
}
private fun IrExpression.adaptIfNecessary(expectedType: KotlinType): IrExpression {
val thisRepresentation = getCustomRepresentation(this.type)
override fun IrExpression.useAsArgument(parameter: ParameterDescriptor): IrExpression {
return this.useAsValue(parameter.original)
}
override fun IrExpression.useForField(field: PropertyDescriptor): IrExpression {
return this.useForVariable(field.original)
}
private fun IrExpression.adaptIfNecessary(actualType: KotlinType, expectedType: KotlinType): IrExpression {
val actualRepresentation = getCustomRepresentation(actualType)
val expectedRepresentation = getCustomRepresentation(expectedType)
return when {
thisRepresentation == expectedRepresentation -> this
actualRepresentation == expectedRepresentation -> this
thisRepresentation == null && expectedRepresentation != null -> {
actualRepresentation == null && expectedRepresentation != null -> {
// This may happen in the following cases:
// 1. `this.type` is `Nothing`;
// 2. `this` has the incompatible type.
// 1. `actualType` is `Nothing`;
// 2. `actualType` is incompatible.
this.unbox(expectedRepresentation)
}
thisRepresentation != null && expectedRepresentation == null -> this.box(thisRepresentation)
actualRepresentation != null && expectedRepresentation == null -> this.box(actualRepresentation)
else -> throw IllegalArgumentException("this is ${this.type}, expected $expectedType")
else -> throw IllegalArgumentException("actual type is $actualType, expected $expectedType")
}
}
@@ -33,19 +33,6 @@ private class BuiltinOperatorTransformer(val context: Context) : IrElementTransf
private val builtIns = context.builtIns
private val irBuiltins = context.irModule!!.irBuiltins
override fun visitTry(aTry: IrTry): IrExpression {
// Workaround for the bug in IrTryImpl.transformChildren: transform `finallyExpression` too.
// TODO: fix the bug and remove it.
val transformer = this
return (aTry as IrTryImpl).apply {
tryResult = tryResult.transform(transformer, null)
catches.forEachIndexed { i, irCatch ->
catches[i] = irCatch.transform(transformer, null)
}
finallyExpression = finallyExpression?.transform(transformer, null)
}
}
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
@@ -201,10 +201,10 @@ private class CallableReferencesUnbinder(val lower: CallableReferenceLowering,
index = index + 1,
annotations = Annotations.EMPTY,
name = param.name,
outType = param.type,
outType = builtIns.nullableAnyType, // Use erased type.
declaresDefaultValue = false,
isCrossinline = false, isNoinline = false,
varargElementType = (param as? ValueParameterDescriptor)?.varargElementType,
varargElementType = null,
source = SourceElement.NO_SOURCE)
}
@@ -223,8 +223,10 @@ private class CallableReferencesUnbinder(val lower: CallableReferenceLowering,
val newValueParameters = listOf(functionParameter) + newUnboundParams
val newReturnType = builtIns.nullableAnyType // Use erased type.
newDescriptor.initialize(null, null, descriptor.typeParameters, newValueParameters,
descriptor.returnType, Modality.FINAL, Visibilities.PRIVATE)
newReturnType, Modality.FINAL, Visibilities.PRIVATE)
return newDescriptor
}
@@ -0,0 +1,269 @@
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.lower.createFunctionIrGenerator
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KonanPlatform
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
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.builders.*
import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
class DefaultParameterStubGenerator internal constructor(val context: Context): DeclarationContainerLoweringPass {
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.declarations.transformFlat { memberDeclaration ->
if (memberDeclaration is IrFunction)
lower(memberDeclaration)
else
null
}
}
object DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER :
IrDeclarationOriginImpl("DEFAULT_PARAMETER_EXTENT")
private fun lower(irFunction: IrFunction): List<IrFunction> {
val bodies = mutableListOf<IrExpressionBody>()
irFunction.acceptChildrenVoid(object:IrElementVisitorVoid{
override fun visitExpressionBody(body: IrExpressionBody) {
bodies.add(body)
}
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
})
val functionDescriptor = irFunction.descriptor
if (bodies.isNotEmpty()) {
val (descriptor, mask, extension, dispatch) = functionDescriptor.generateDefaultsDescriptor()
val generator = context.createFunctionIrGenerator(descriptor)
val builder = generator.createIrBuilder()
builder.apply {
startOffset = irFunction.startOffset
endOffset = irFunction.endOffset
}
val body = generator.irBlockBody {
val params = mutableListOf<VariableDescriptor>()
val variables = mutableMapOf<VariableDescriptor, VariableDescriptor>()
for (valueParameter in functionDescriptor.valueParameters) {
val parameterDescriptor = descriptor.valueParameters[valueParameter.index]
if (valueParameter.hasDefaultValue()) {
val variable = scope.createTemporaryVariable(
irExpression = nullConst(valueParameter.type)!!,
isMutable = true)
val variableDescriptor = variable.descriptor
params.add(variableDescriptor)
+variable
val condition = irNotEquals(irCall(intAnd).apply {
dispatchReceiver = irGet(mask)
putValueArgument(0, irInt(1 shl valueParameter.index))
}, irInt(0))
val exprBody = getDefaultParameterExpressionBody(irFunction, valueParameter)
/* Use previously calculated values in next expression. */
exprBody.expression.transformChildrenVoid(object:IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
if (!variables.containsKey(expression.descriptor))
return expression
return irGet(variables[expression.descriptor] as VariableDescriptor)
}
})
/* Mapping calculated values with its origin variables. */
variables.put(valueParameter, variableDescriptor)
+irIfThenElse(
type = KonanPlatform.builtIns.unitType,
condition = condition,
thenPart = irSetVar(variableDescriptor, exprBody.expression),
elsePart = irSetVar(variableDescriptor, irGet(parameterDescriptor)))
} else {
params.add(parameterDescriptor)
}
}
+ irReturn(irCall(functionDescriptor).apply {
if (functionDescriptor.dispatchReceiverParameter != null) {
dispatchReceiver = irGet(dispatch!!)
}
if (functionDescriptor.extensionReceiverParameter != null) {
extensionReceiver = irGet(extension!!)
}
params.forEachIndexed { i, variable ->
putValueArgument(i, irGet(variable))
}
})
}
// TODO: replace irFunction with new one without expression bodies.
return listOf(irFunction, IrFunctionImpl(
irFunction.startOffset ,
irFunction.endOffset,
DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER,
descriptor, body))
}
return irFunction.singletonList()
}
}
private fun getDefaultParameterExpressionBody(irFunction: IrFunction, valueParameter: ValueParameterDescriptor):IrExpressionBody {
return irFunction.getDefault(valueParameter) as? IrExpressionBody ?: TODO("FIXME!!!")
}
private fun nullConst(type: KotlinType): IrExpression? {
when {
KotlinBuiltIns.isFloat(type) -> return IrConstImpl<Float> (0, 0, type, IrConstKind.Float, 0.0F)
KotlinBuiltIns.isDouble(type) -> return IrConstImpl<Double> (0, 0, type, IrConstKind.Double, 0.0)
KotlinBuiltIns.isBoolean(type) -> return IrConstImpl<Boolean> (0, 0, type, IrConstKind.Boolean, false)
KotlinBuiltIns.isByte(type) -> return IrConstImpl<Byte> (0, 0, type, IrConstKind.Byte, 0)
KotlinBuiltIns.isShort(type) -> return IrConstImpl<Short> (0, 0, type, IrConstKind.Short, 0)
KotlinBuiltIns.isInt(type) -> return IrConstImpl<Int> (0, 0, type, IrConstKind.Int, 0)
KotlinBuiltIns.isLong(type) -> return IrConstImpl<Long> (0, 0, type, IrConstKind.Long, 0)
else -> return IrConstImpl<Nothing?>(0, 0, type, IrConstKind.Null, null)
}
}
class DefaultParameterInjector internal constructor(val context: Context): BodyLoweringPass {
override fun lower(irBody: IrBody) {
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression {
super.visitCall(expression)
val descriptor = expression.descriptor
if (descriptor.valueParameters.none{it.hasDefaultValue()})
return expression
var argumentsCount = 0
expression.acceptChildrenVoid(object:IrElementVisitorVoid{
override fun visitElement(element: IrElement) {
argumentsCount++
}
})
if (descriptor.dispatchReceiverParameter != null || descriptor.extensionReceiverParameter != null)
argumentsCount--
if (argumentsCount == descriptor.valueParameters.size)
return expression
var maskValue = 0
val functionDescriptor = descriptor as FunctionDescriptor
val (defaultFunctiondescriptor, mask, extension, dispatch) = functionDescriptor.generateDefaultsDescriptor()
val params = descriptor.valueParameters.mapIndexed { i, it ->
if (expression.getValueArgument(i) == null) maskValue = maskValue or (1 shl i)
val valueParameterDescriptor = defaultFunctiondescriptor.valueParameters[i]
return@mapIndexed valueParameterDescriptor to (expression.getValueArgument(i) ?: nullConst(valueParameterDescriptor.type))
} + (mask to IrConstImpl<Int>(
startOffset = irBody.startOffset,
endOffset = irBody.endOffset,
type = KonanPlatform.builtIns.intType,
kind = IrConstKind.Int,
value = maskValue))
return IrCallImpl(
startOffset = irBody.startOffset,
endOffset = irBody.endOffset,
type = descriptor.returnType!!,
descriptor = defaultFunctiondescriptor,
typeArguments = null)
.apply {
params.forEach {
putValueArgument(it.first.index, it.second)
}
extension?.apply {
putValueArgument(extension.index, expression.extensionReceiver)
}
dispatch?.apply {
putValueArgument(dispatch.index, expression.dispatchReceiver)
}
}
}
})
}
}
val intDesctiptor = DescriptorUtils.getClassDescriptorForType(KonanPlatform.builtIns.intType)
val intAnd = DescriptorUtils.getFunctionByName(intDesctiptor.unsubstitutedMemberScope, Name.identifier("and"))
data class DefaultParameterDescriptor(val function: FunctionDescriptor, val mask:ValueParameterDescriptor,
val extensionReceiver:ValueParameterDescriptor?, val dispatchReceiver: ValueParameterDescriptor?)
fun FunctionDescriptor.generateDefaultsDescriptor():DefaultParameterDescriptor {
val name = Name.identifier("${this.name.asString()}\$default")
val descriptor = SimpleFunctionDescriptorImpl.create(this.containingDeclaration, Annotations.EMPTY,
name, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE)
val maskVariable = valueParameter(descriptor, valueParameters.size, "__\$mask\$__", KonanPlatform.builtIns.intType)
var extensionReceiver:ValueParameterDescriptor? = null
var index = valueParameters.size + 1
extensionReceiverParameter?.let {
extensionReceiver = valueParameter(descriptor, index++, "__\$ext_receiver\$__", extensionReceiverParameter!!.type)
}
var dispatchReceiver:ValueParameterDescriptor? = null
dispatchReceiverParameter?.let {
dispatchReceiver = valueParameter(descriptor, index++, "__\$dispatch_receiver\$__", dispatchReceiverParameter!!.type)
}
val parameterList = mutableListOf(*valueParameters.map{
if (it.hasDefaultValue()) ValueParameterDescriptorImpl(
containingDeclaration = it.containingDeclaration,
original = it.original,
index = it.index,
annotations = it.annotations,
name = it.name,
outType = it.type,
declaresDefaultValue = false,
isCrossinline = it.isCrossinline,
isNoinline = it.isNoinline,
varargElementType = it.varargElementType,
source = it.source)
else it
}.toTypedArray())
parameterList.add(maskVariable)
if (extensionReceiver != null) parameterList.add(extensionReceiver)
if (dispatchReceiver != null) parameterList.add(dispatchReceiver)
descriptor.initialize(
/* receiverParameterType = */ null,
/* dispatchReceiverParameterType = */ null,
/* typeParameters = */ typeParameters,
/* unsubstitutedValueParameters = */ parameterList,
/* unsubstitutedReturnType = */ returnType,
/* modality = */ this.modality,
/* visibility = */ this.visibility)
return DefaultParameterDescriptor(descriptor, maskVariable, extensionReceiver, dispatchReceiver)
}
private fun valueParameter(descriptor: FunctionDescriptor, index: Int, name: String, type: KotlinType):ValueParameterDescriptor {
return ValueParameterDescriptorImpl(
containingDeclaration = descriptor,
original = null,
index = index,
annotations = Annotations.EMPTY,
name = Name.identifier(name),
outType = type,
declaresDefaultValue = false,
isCrossinline = false,
isNoinline = false,
varargElementType = null,
source = SourceElement.NO_SOURCE
)
}
@@ -1,138 +0,0 @@
/*
* 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.ir.builders
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.types.KotlinType
inline fun IrBuilderWithScope.irLet(
value: IrExpression,
origin: IrStatementOrigin? = null,
nameHint: String? = null,
body: (VariableDescriptor) -> IrExpression
): IrExpression {
val irTemporary = scope.createTemporaryVariable(value, nameHint)
val irResult = body(irTemporary.descriptor)
val irBlock = IrBlockImpl(startOffset, endOffset, irResult.type, origin)
irBlock.statements.add(irTemporary)
irBlock.statements.add(irResult)
return irBlock
}
fun <T : IrElement> IrStatementsBuilder<T>.defineTemporary(value: IrExpression, nameHint: String? = null): VariableDescriptor {
val temporary = scope.createTemporaryVariable(value, nameHint)
+temporary
return temporary.descriptor
}
fun <T : IrElement> IrStatementsBuilder<T>.defineTemporaryVar(value: IrExpression, nameHint: String? = null): VariableDescriptor {
val temporary = scope.createTemporaryVariable(value, nameHint, isMutable = true)
+temporary
return temporary.descriptor
}
fun IrBuilderWithScope.irReturn(value: IrExpression) =
IrReturnImpl(startOffset, endOffset, context.builtIns.nothingType, scope.assertCastOwner(), value)
fun IrBuilderWithScope.irReturnTrue() =
irReturn(IrConstImpl(startOffset, endOffset, context.builtIns.booleanType, IrConstKind.Boolean, true))
fun IrBuilderWithScope.irReturnFalse() =
irReturn(IrConstImpl(startOffset, endOffset, context.builtIns.booleanType, IrConstKind.Boolean, false))
fun IrBuilderWithScope.irIfThenElse(type: KotlinType, condition: IrExpression, thenPart: IrExpression, elsePart: IrExpression) =
IrIfThenElseImpl(startOffset, endOffset, type, condition, thenPart, elsePart)
fun IrBuilderWithScope.irIfNull(type: KotlinType, subject: IrExpression, thenPart: IrExpression, elsePart: IrExpression) =
irIfThenElse(type, irEqualsNull(subject), thenPart, elsePart)
fun IrBuilderWithScope.irThrowNpe(origin: IrStatementOrigin) =
IrNullaryPrimitiveImpl(startOffset, endOffset, origin, context.irBuiltIns.throwNpe)
fun IrBuilderWithScope.irIfThenReturnTrue(condition: IrExpression) =
IrIfThenElseImpl(startOffset, endOffset, context.builtIns.unitType, condition, irReturnTrue())
fun IrBuilderWithScope.irIfThenReturnFalse(condition: IrExpression) =
IrIfThenElseImpl(startOffset, endOffset, context.builtIns.unitType, condition, irReturnFalse())
fun IrBuilderWithScope.irThis() =
scope.classOwner().let { classOwner ->
IrGetValueImpl(startOffset, endOffset, classOwner.thisAsReceiverParameter)
}
fun IrBuilderWithScope.irGet(variable: VariableDescriptor) =
IrGetValueImpl(startOffset, endOffset, variable)
fun IrBuilderWithScope.irSetVar(variable: VariableDescriptor, value: IrExpression) =
IrSetVariableImpl(startOffset, endOffset, variable, value, IrStatementOrigin.EQ)
fun IrBuilderWithScope.irOther() =
irGet(scope.functionOwner().valueParameters.single())
fun IrBuilderWithScope.irEqeqeq(arg1: IrExpression, arg2: IrExpression) =
context.eqeqeq(startOffset, endOffset, arg1, arg2)
fun IrBuilderWithScope.irNull() =
IrConstImpl.constNull(startOffset, endOffset, context.builtIns.nullableNothingType)
fun IrBuilderWithScope.irEqualsNull(argument: IrExpression) =
primitiveOp2(startOffset, endOffset, context.irBuiltIns.eqeq, IrStatementOrigin.EQEQ,
argument, irNull())
fun IrBuilderWithScope.irNotEquals(arg1: IrExpression, arg2: IrExpression) =
primitiveOp1(startOffset, endOffset, context.irBuiltIns.booleanNot, IrStatementOrigin.EXCLEQ,
primitiveOp2(startOffset, endOffset, context.irBuiltIns.eqeq, IrStatementOrigin.EXCLEQ,
arg1, arg2))
fun IrBuilderWithScope.irGet(receiver: IrExpression, property: PropertyDescriptor): IrExpression =
IrGetterCallImpl(startOffset, endOffset, property.getter!!, null, receiver, null, IrStatementOrigin.GET_PROPERTY)
fun IrBuilderWithScope.irCall(callee: CallableDescriptor) =
IrCallImpl(startOffset, endOffset, callee.returnType!!, callee, null)
fun IrBuilderWithScope.irCallOp(callee: CallableDescriptor, dispatchReceiver: IrExpression, argument: IrExpression) =
IrCallImpl(startOffset, endOffset, callee.returnType!!, callee, null).apply {
this.dispatchReceiver = dispatchReceiver
putValueArgument(0, argument)
}
fun IrBuilderWithScope.irIs(argument: IrExpression, type: KotlinType) =
IrTypeOperatorCallImpl(startOffset, endOffset, context.builtIns.booleanType, IrTypeOperator.INSTANCEOF, type, argument)
fun IrBuilderWithScope.irNotIs(argument: IrExpression, type: KotlinType) =
IrTypeOperatorCallImpl(startOffset, endOffset, context.builtIns.booleanType, IrTypeOperator.NOT_INSTANCEOF, type, argument)
fun IrBuilderWithScope.irAs(argument: IrExpression, type: KotlinType) =
IrTypeOperatorCallImpl(startOffset, endOffset, type, IrTypeOperator.CAST, type, argument)
fun IrBuilderWithScope.irImplicitCast(argument: IrExpression, type: KotlinType) =
IrTypeOperatorCallImpl(startOffset, endOffset, type, IrTypeOperator.IMPLICIT_CAST, type, argument)
fun IrBuilderWithScope.irInt(value: Int) =
IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, value)
fun IrBuilderWithScope.irString(value: String) =
IrConstImpl.string(startOffset, endOffset, context.builtIns.stringType, value)
fun IrBuilderWithScope.irConcat() =
IrStringConcatenationImpl(startOffset, endOffset, context.builtIns.stringType)
@@ -1,35 +0,0 @@
/*
* 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.ir.builders
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
// TODO: rename Generator* to IrGenerator* when contributing back to Kotlin.
interface Generator {
val context: GeneratorContext
}
interface GeneratorWithScope : Generator {
val scope: Scope
}
interface GeneratorContext {
val irBuiltIns: IrBuiltIns
val builtIns: KotlinBuiltIns get() = irBuiltIns.builtIns
}
@@ -1,127 +0,0 @@
/*
* 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.ir.builders
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.types.KotlinType
import java.util.*
abstract class IrBuilder(
override val context: GeneratorContext,
var startOffset: Int,
var endOffset: Int
) : Generator
abstract class IrBuilderWithScope(
context: GeneratorContext,
override val scope: Scope,
startOffset: Int,
endOffset: Int
) : IrBuilder(context, startOffset, endOffset), GeneratorWithScope
abstract class IrStatementsBuilder<out T : IrElement>(
context: GeneratorContext,
scope: Scope,
startOffset: Int,
endOffset: Int
) : IrBuilderWithScope(context, scope, startOffset, endOffset) {
operator fun IrStatement.unaryPlus() {
addStatement(this)
}
protected abstract fun addStatement(irStatement: IrStatement)
protected abstract fun doBuild(): T
}
open class IrBlockBodyBuilder(
context: GeneratorContext,
scope: Scope,
startOffset: Int,
endOffset: Int
) : IrStatementsBuilder<IrBlockBody>(context, scope, startOffset, endOffset) {
private val irBlockBody = IrBlockBodyImpl(startOffset, endOffset)
inline fun blockBody(body: IrBlockBodyBuilder.() -> Unit): IrBlockBody {
body()
return doBuild()
}
override fun addStatement(irStatement: IrStatement) {
irBlockBody.statements.add(irStatement)
}
override fun doBuild(): IrBlockBody {
return irBlockBody
}
}
class IrBlockBuilder(
context: GeneratorContext, scope: Scope,
startOffset: Int, endOffset: Int,
val origin: IrStatementOrigin? = null,
var resultType: KotlinType? = null
) : IrStatementsBuilder<IrBlock>(context, scope, startOffset, endOffset) {
private val statements = ArrayList<IrStatement>()
inline fun block(body: IrBlockBuilder.() -> Unit): IrBlock {
body()
return doBuild()
}
override fun addStatement(irStatement: IrStatement) {
statements.add(irStatement)
}
override fun doBuild(): IrBlock {
val resultType = this.resultType ?:
(statements.lastOrNull() as? IrExpression)?.type ?:
context.builtIns.unitType
val irBlock = IrBlockImpl(startOffset, endOffset, resultType, origin)
irBlock.statements.addAll(statements)
return irBlock
}
}
fun <T : IrBuilder> T.at(startOffset: Int, endOffset: Int): T {
this.startOffset = startOffset
this.endOffset = endOffset
return this
}
inline fun GeneratorWithScope.irBlock(startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET,
origin: IrStatementOrigin? = null,
resultType: KotlinType? = null,
body: IrBlockBuilder.() -> Unit
): IrExpression =
IrBlockBuilder(context, scope,
startOffset,
endOffset,
origin, resultType
).block(body)
inline fun GeneratorWithScope.irBlockBody(startOffset: Int = UNDEFINED_OFFSET, endOffset: Int = UNDEFINED_OFFSET,
body: IrBlockBodyBuilder.() -> Unit
) : IrBlockBody =
IrBlockBodyBuilder(context, scope,
startOffset,
endOffset
).blockBody(body)
@@ -1,39 +0,0 @@
/*
* 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.ir.builders
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
class IrMemberFunctionBuilder(
context: GeneratorContext,
val irClass: IrClassImpl,
val function: FunctionDescriptor,
val origin: IrDeclarationOrigin,
startOffset: Int = UNDEFINED_OFFSET,
endOffset: Int = UNDEFINED_OFFSET
) : IrBlockBodyBuilder(context, Scope(function), startOffset, endOffset) {
inline fun addToClass(body: IrMemberFunctionBuilder.() -> Unit) {
val irFunction = IrFunctionImpl(startOffset, endOffset, origin, function)
body()
irFunction.body = doBuild()
irClass.addMember(irFunction)
}
}
@@ -1,64 +0,0 @@
/*
* 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.ir.builders
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
fun primitiveOp1(startOffset: Int, endOffset: Int, primitiveOpDescriptor: CallableDescriptor, origin: IrStatementOrigin,
argument: IrExpression): IrExpression =
IrUnaryPrimitiveImpl(startOffset, endOffset, origin, primitiveOpDescriptor, argument)
fun primitiveOp2(startOffset: Int, endOffset: Int, primitiveOpDescriptor: CallableDescriptor, origin: IrStatementOrigin,
argument1: IrExpression, argument2: IrExpression): IrExpression =
IrBinaryPrimitiveImpl(startOffset, endOffset, origin, primitiveOpDescriptor, argument1, argument2)
fun GeneratorContext.constNull(startOffset: Int, endOffset: Int): IrExpression =
IrConstImpl.constNull(startOffset, endOffset, builtIns.nullableNothingType)
fun GeneratorContext.equalsNull(startOffset: Int, endOffset: Int, argument: IrExpression): IrExpression =
primitiveOp2(startOffset, endOffset, irBuiltIns.eqeq, IrStatementOrigin.EQEQ,
argument, constNull(startOffset, endOffset))
fun GeneratorContext.eqeqeq(startOffset: Int, endOffset: Int, argument1: IrExpression, argument2: IrExpression): IrExpression =
primitiveOp2(startOffset, endOffset, irBuiltIns.eqeqeq, IrStatementOrigin.EQEQEQ, argument1, argument2)
fun GeneratorContext.throwNpe(startOffset: Int, endOffset: Int, origin: IrStatementOrigin): IrExpression =
IrNullaryPrimitiveImpl(startOffset, endOffset, origin, irBuiltIns.throwNpe)
// a || b == if (a) true else b
fun GeneratorContext.oror(startOffset: Int, endOffset: Int, a: IrExpression, b: IrExpression, origin: IrStatementOrigin = IrStatementOrigin.OROR): IrWhen =
IrIfThenElseImpl(startOffset, endOffset, builtIns.booleanType,
a, IrConstImpl.constTrue(b.startOffset, b.endOffset, b.type), b,
origin)
fun GeneratorContext.oror(a: IrExpression, b: IrExpression, origin: IrStatementOrigin = IrStatementOrigin.OROR): IrWhen =
oror(b.startOffset, b.endOffset, a, b, origin)
fun GeneratorContext.whenComma(a: IrExpression, b: IrExpression): IrWhen =
oror(a, b, IrStatementOrigin.WHEN_COMMA)
// a && b == if (a) b else false
fun GeneratorContext.andand(startOffset: Int, endOffset: Int, a: IrExpression, b: IrExpression, origin: IrStatementOrigin = IrStatementOrigin.ANDAND): IrWhen =
IrIfThenElseImpl(startOffset, endOffset, builtIns.booleanType,
a, b, IrConstImpl.constFalse(b.startOffset, b.endOffset, b.type),
origin)
fun GeneratorContext.andand(a: IrExpression, b: IrExpression, origin: IrStatementOrigin = IrStatementOrigin.ANDAND): IrWhen =
andand(b.startOffset, b.endOffset, a, b, origin)
@@ -1,47 +0,0 @@
/*
* 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.ir.builders
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptor
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
class Scope(val scopeOwner: DeclarationDescriptor) {
private var lastTemporaryIndex: Int = 0
private fun nextTemporaryIndex(): Int = lastTemporaryIndex++
private fun createDescriptorForTemporaryVariable(type: KotlinType, nameHint: String? = null, isMutable: Boolean = false): IrTemporaryVariableDescriptor =
IrTemporaryVariableDescriptorImpl(scopeOwner, Name.identifier(getNameForTemporary(nameHint)), type, isMutable)
private fun getNameForTemporary(nameHint: String?): String {
val index = nextTemporaryIndex()
return if (nameHint != null) "tmp${index}_$nameHint" else "tmp$index"
}
fun createTemporaryVariable(irExpression: IrExpression, nameHint: String? = null, isMutable: Boolean = false): IrVariable =
IrVariableImpl(
irExpression.startOffset, irExpression.endOffset, IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
createDescriptorForTemporaryVariable(irExpression.type, nameHint, isMutable),
irExpression
)
}
@@ -1,33 +0,0 @@
/*
* 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.ir.builders
import org.jetbrains.kotlin.descriptors.*
inline fun <reified T> Scope.assertCastOwner() =
scopeOwner as? T ?:
throw AssertionError("Unexpected scopeOwner: $scopeOwner")
fun Scope.functionOwner(): FunctionDescriptor =
assertCastOwner()
fun Scope.classOwner(): ClassDescriptor =
when (scopeOwner) {
is ClassDescriptor -> scopeOwner
is MemberDescriptor -> scopeOwner.containingDeclaration as ClassDescriptor
else -> throw AssertionError("Unexpected scopeOwner: $scopeOwner")
}
+2 -1
View File
@@ -10,12 +10,13 @@ libGcc.linux = target-gcc-toolchain-3-linux-x86-64/lib/gcc/x86_64-unknown-linux-
llvmLtoFlags.osx = -O3 -function-sections -exported-symbol=_main
llvmLlcFlags.osx = -mtriple=x86_64-apple-macosx10.10.0
linkerKonanFlags.osx = -lc++
linkerOptimizationFlags.osx = -dead_strip
macosVersionMin.osx = 10.10.0
llvmLtoFlags.linux = -O3 -function-sections -exported-symbol=main
llvmLlcFlags.linux = -march=x86-64
linkerKonanFlags.linux = -Bstatic -lc++abi -Bdynamic -ldl -lm -lpthread
linkerKonanFlags.linux = -Bstatic -lstdc++ -Bdynamic -ldl -lm -lpthread
linkerOptimizationFlags.linux = --gc-sections
pluginOptimizationFlags.linux = -plugin-opt=mcpu=x86-64 -plugin-opt=O3
+67 -9
View File
@@ -41,11 +41,11 @@ abstract class KonanTest extends DefaultTask {
project.javaexec {
main = 'org.jetbrains.kotlin.cli.bc.K2NativeKt'
classpath = project.configurations.cli_bc
jvmArgs "-ea",
jvmArgs "-ea",
"-Dkonan.home=${dist.canonicalPath}",
"-Djava.library.path=${dist.canonicalPath}/konan/nativelib"
args("-output", output,
source,
source,
*moreArgs,
*project.globalArgs)
}
@@ -88,7 +88,7 @@ abstract class KonanTest extends DefaultTask {
class RunKonanTest extends KonanTest {
void compileTest(String source, String exe) {
runCompiler(source, exe, [])
runCompiler(source, exe, [])
}
}
@@ -98,7 +98,7 @@ class LinkKonanTest extends KonanTest {
void compileTest(String source, String exe) {
def libDir = project.file(lib).absolutePath
def libBc = "${libDir}.bc"
runCompiler(lib, libBc, ['-nolink', '-nostdlib'])
runCompiler(source, exe, ['-library', libBc])
}
@@ -149,6 +149,12 @@ task objectInitialization(type: RunKonanTest) {
source = "codegen/object/initialization.kt"
}
task objectInitialization1(type: RunKonanTest) {
disabled = true
goldValue = "init\nfield\nconstructor1\ninit\nfield\nconstructor1\nconstructor2\n"
source = "codegen/object/initialization1.kt"
}
task check_type(type: RunKonanTest) {
goldValue = "true\nfalse\ntrue\ntrue\ntrue\ntrue\n"
source = "codegen/basics/check_type.kt"
@@ -173,6 +179,41 @@ task sum2(type: RunKonanTest) {
source = "codegen/function/sum_imm.kt"
}
task defaults(type: RunKonanTest) {
source = "codegen/function/defaults.kt"
}
task defaults1(type: RunKonanTest) {
source = "codegen/function/defaults1.kt"
}
task defaults2(type: RunKonanTest) {
source = "codegen/function/defaults2.kt"
}
task defaults3(type: RunKonanTest) {
source = "codegen/function/defaults3.kt"
}
task defaults4(type: RunKonanTest) {
disabled = true
goldValue = "43\n"
source = "codegen/function/defaults4.kt"
}
task defaults5(type: RunKonanTest) {
disabled = true
goldValue = "5\n6\n"
source = "codegen/function/defaults5.kt"
}
task defaults6(type: RunKonanTest) {
disabled = true
goldValue = "42\n"
source = "codegen/function/defaults6.kt"
}
task sum_3const(type: RunKonanTest) {
source = "codegen/function/sum_3const.kt"
}
@@ -195,7 +236,6 @@ task null_check(type: RunKonanTest) {
}
task array_to_any(type: RunKonanTest) {
disabled = true
source = "codegen/basics/array_to_any.kt"
}
@@ -247,8 +287,8 @@ task tostring3(type: RunKonanTest) {
"1.17549E-38\n3.40282E+38\n-INF\nINF\n" +
// Linux version prints -NAN.
// "NAN\n" +
"4.94066E-324\n1.79769E+308\n-INF\nINF\n"
// "NAN\n"
"4.94066E-324\n1.79769E+308\n-INF\nINF\n"
// "NAN\n"
source = "runtime/basic/tostring3.kt"
}
@@ -267,6 +307,11 @@ task array1(type: RunKonanTest) {
source = "runtime/collections/array1.kt"
}
task array2(type: RunKonanTest) {
goldValue = "0\n2\n4\n6\n8\n40\n"
source = "runtime/collections/array2.kt"
}
task if_else(type: RunKonanTest) {
source = "codegen/branching/if_else.kt"
}
@@ -308,6 +353,11 @@ task bool_yes(type: RunKonanTest) {
source = "codegen/function/boolean.kt"
}
task named(type: RunKonanTest) {
source = "codegen/function/named.kt"
}
task plus_eq(type: RunKonanTest) {
source = "codegen/function/plus_eq.kt"
}
@@ -360,7 +410,7 @@ task intrinsic(type: RunKonanTest) {
}
/*
Disabled until we extract the classes that should be
Disabled until we extract the classes that should be
always present from stdlib.kt.bc into a separate binary.
task link(type: LinkKonanTest) {
@@ -386,7 +436,6 @@ task statements0(type: RunKonanTest) {
}
task boxing0(type: RunKonanTest) {
disabled = true
goldValue = "17\n"
source = "codegen/boxing/boxing0.kt"
}
@@ -498,6 +547,10 @@ task moderately_large_array(type: RunKonanTest) {
source = "runtime/collections/moderately_large_array.kt"
}
task moderately_large_array1(type: RunKonanTest) {
goldValue = "-45392\n"
source = "runtime/collections/moderately_large_array1.kt"
}
task string_builder0(type: RunKonanTest) {
goldValue = "OK\n"
@@ -807,6 +860,11 @@ task memory_throw_cleanup(type: RunKonanTest) {
source = "runtime/memory/throw_cleanup.kt"
}
task memory_collect_cycles(type: RunKonanTest) {
goldValue = "42\n"
source = "runtime/memory/cycles0.kt"
}
task unit1(type: RunKonanTest) {
goldValue = "First\nkotlin.Unit\n"
source = "codegen/basics/unit1.kt"
@@ -1,7 +1,7 @@
fun main(args: Array<String>) {
println(foo().toString())
foo().hashCode()
}
fun foo(): Any {
return Array<Any?>(0)
return Array<Any?>(0, { i -> null })
}
@@ -0,0 +1,97 @@
/**
* Created by minamoto on 12/26/16.
*/
//package defaults
open class A(val a:Int) {
override fun equals(other: Any?): Boolean {
if (other == null || other as? A == null) return false
return (other as A).a == a // Where is smart casting?
}
companion object {
val zero = A(0)
val one = A(1)
val magic = A(42)
}
}
// FUN public fun foo(a: defaults.A = ...): kotlin.Int
// a: EXPRESSION_BODY
// CALL '<get-magic>(): A' type=defaults.A origin=GET_PROPERTY
// $this: GET_OBJECT 'companion object of A' type=defaults.A.Companion
// BLOCK_BODY
// RETURN type=kotlin.Nothing from='foo(A = ...): Int'
// CALL '<get-a>(): Int' type=kotlin.Int origin=GET_PROPERTY
// $this: GET_VAR 'value-parameter a: A = ...' type=defaults.A origin=null
fun foo(a: A = A.magic, b:Int = 0xdeadbeef.toInt()) = a.a
// FUN public fun bar(a: defaults.A, inc: kotlin.Int = ...): defaults.A
// inc: EXPRESSION_BODY
// CONST Int type=kotlin.Int value='0'
// BLOCK_BODY
// RETURN type=kotlin.Nothing from='bar(A, Int = ...): A'
// CALL 'constructor A(Int)' type=defaults.A origin=null
// a: CALL 'plus(Int): Int' type=kotlin.Int origin=PLUS
// $this: CALL '<get-a>(): Int' type=kotlin.Int origin=GET_PROPERTY
// $this: GET_VAR 'value-parameter a: A' type=defaults.A origin=null
// other: GET_VAR 'value-parameter inc: Int = ...' type=kotlin.Int origin=null
fun bar(a:A, inc:Int = 0) = A(a.a + inc)
fun main(args:Array<String>) {
// if: CALL 'NOT(Boolean): Boolean' type=kotlin.Boolean origin=EXCLEQ
// arg0: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EXCLEQ
// arg0: CALL 'foo(A = ...): Int' type=kotlin.Int origin=null
// arg1: CALL '<get-a>(): Int' type=kotlin.Int origin=GET_PROPERTY
// $this: CALL '<get-magic>(): A' type=defaults.A origin=GET_PROPERTY
// $this: GET_OBJECT 'companion object of A' type=defaults.A.Companion
if (foo() != A.magic.a) {
println("magic failed")
throw Error()
}
// if: CALL 'NOT(Boolean): Boolean' type=kotlin.Boolean origin=EXCLEQ
// arg0: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EXCLEQ
// arg0: CALL 'foo(A = ...): Int' type=kotlin.Int origin=null
// a: CALL 'constructor A(Int)' type=defaults.A origin=null
// a: CONST Int type=kotlin.Int value='1'
// arg1: CONST Int type=kotlin.Int value='1'
if (foo(A(1)) != 1) {
println("one failed: foo(A(1))")
throw Error()
}
// if: CALL 'NOT(Boolean): Boolean' type=kotlin.Boolean origin=EXCLEQ
// arg0: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EXCLEQ
// arg0: CALL 'bar(A, Int = ...): A' type=defaults.A origin=null
// a: CALL '<get-one>(): A' type=defaults.A origin=GET_PROPERTY <---
// $this: GET_OBJECT 'companion object of A' type=defaults.A.Companion
// arg1: CALL '<get-one>(): A' type=defaults.A origin=GET_PROPERTY
// $this: GET_OBJECT 'companion object of A' type=defaults.A.Companion
if (bar(A.one) != A.one) {
println("A one failed")
throw Error()
}
// if: CALL 'NOT(Boolean): Boolean' type=kotlin.Boolean origin=EXCLEQ
// arg0: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EXCLEQ
// arg0: CALL '<get-a>(): Int' type=kotlin.Int origin=GET_PROPERTY
// $this: CALL 'bar(A, Int = ...): A' type=defaults.A origin=null
// a: CALL '<get-one>(): A' type=defaults.A origin=GET_PROPERTY
// $this: GET_OBJECT 'companion object of A' type=defaults.A.Companion
// inc: CONST Int type=kotlin.Int value='1'
// arg1: CONST Int type=kotlin.Int value='2'
if (bar(A.one, 1).a != 2) {
println("A one + 1 failed")
throw Error()
}
println("all tests passed")
}
@@ -0,0 +1,9 @@
fun foo(x:Int = 0, y:Int = x + 1, z:Int = x + y + 1) = x + y + z
fun main(arg:Array<String>) {
val v = foo()
if (v != 3) {
println("test failed $v expected 3")
throw Error()
}
}
@@ -0,0 +1,10 @@
fun Int.foo(inc0:Int, inc:Int = 0) = this + inc0 + inc
fun main(arg:Array<String>) {
val v = 42.foo(0)
if (v != 42) {
println("test failed v:$v expected:42")
throw Error()
}
}
@@ -0,0 +1,12 @@
fun foo(a:Int = 2, b:String = "Hello", c:Int = 4):String = "$b-$c$a"
fun foo(a:Int = 3, b:Int = a + 1, c:Int = a + b) = a + b + c
fun main(arg:Array<String>){
val a = foo(b="Universe")
if (a != "Universe-42")
throw Error()
val b = foo(b = 5)
if (b != (/* a = */ 3 + /* b = */ 5 + /* c = */ (3 + 5)))
throw Error()
}
@@ -0,0 +1,11 @@
open class A {
open fun foo(x: Int = 42) = println(x)
}
class B : A() {
override fun foo(x: Int) = println(x + 1)
}
fun main(args: Array<String>) {
B().foo()
}
@@ -0,0 +1,14 @@
class Test(val x: Int) {
fun foo(y: Int = x) {
println(y)
}
}
fun Test.bar(y: Int = x) {
println(y)
}
fun main(args: Array<String>) {
Test(5).foo()
Test(6).bar()
}
@@ -0,0 +1,6 @@
open class Foo(val x: Int = 42)
class Bar : Foo()
fun main(args: Array<String>) {
println(Bar().x)
}
@@ -0,0 +1,5 @@
fun foo(a:Int, b:Int) = a - b
fun main(args:Array<String>) {
if (foo(b = 24, a = 42) != 18)
throw Error()
}
@@ -0,0 +1,20 @@
class Test {
constructor() {
println("constructor1")
}
constructor(x: Int) : this() {
println("constructor2")
}
init {
println("init")
}
val f = println("field")
}
fun main(args: Array<String>) {
Test()
Test(1)
}
@@ -24,6 +24,6 @@ fun main(args : Array<String>) {
val booleanArray = BooleanArray(12)
println(booleanArray.size.toString())
val stringArray = Array<String>(13)
val stringArray = Array<String>(13, { i -> ""})
println(stringArray.size.toString())
}
@@ -0,0 +1,7 @@
fun main(args : Array<String>) {
val byteArray = Array<Byte>(5, { i -> (i * 2).toByte() })
byteArray.map { println(it) }
val intArray = Array<Int>(5, { i -> i * 4 })
println(intArray.sum())
}
@@ -181,7 +181,6 @@ fun testPutEntry() {
assertTrue(expected == m)
}
/* Fails due to variance.
fun testRemoveAllEntries() {
val expected = mapOf("a" to "1", "b" to "2", "c" to "3")
val m = HashMap(expected)
@@ -199,7 +198,7 @@ fun testRetainAllEntries() {
assertEquals(expected, m)
assertTrue(m.entries.retainAll(mapOf("b" to "22", "c" to "3", "d" to "4").entries))
assertEquals(mapOf("c" to "3"), m)
} */
}
fun testContainsAllValues() {
val m = HashMap(mapOf("a" to "1", "b" to "2", "c" to "3"))
@@ -256,8 +255,8 @@ fun main(args : Array<String>) {
testHashCode()
testToString()
testPutEntry()
//testRemoveAllEntries()
//testRetainAllEntries()
testRemoveAllEntries()
testRetainAllEntries()
testContainsAllValues()
testRemoveValue()
testRemoveAllValues()
@@ -0,0 +1,11 @@
fun main(args: Array<String>) {
val a = Array<Byte>(100000, { i -> i.toByte()})
var sum = 0
for (b in a) {
sum += b
}
println(sum)
}
@@ -0,0 +1,45 @@
data class Node(val data: Int, var next: Node?, var prev: Node?, val outer: Node?)
fun makeCycle(len: Int, outer: Node?): Node {
val start = Node(0, null, null, outer)
var prev = start
for (i in 1 .. len - 1) {
prev = Node(i, prev, null, outer)
}
start.next = prev
return start
}
fun makeDoubleCycle(len: Int): Node {
val start = makeCycle(len, null)
var prev = start
var cur = prev.next
while (cur != start) {
cur!!.prev = prev
prev = cur
cur = cur.next
}
start.prev = prev
return start
}
fun createCycles(junk: Node) {
val cycle1 = makeCycle(1, junk)
val cycle2 = makeCycle(2, junk)
val cycle10 = makeCycle(10, junk)
val cycle100 = makeCycle(100, junk)
val dcycle1 = makeDoubleCycle(1)
val dcycle2 = makeDoubleCycle(2)
val dcycle10 = makeDoubleCycle(10)
val dcycle100 = makeDoubleCycle(100)
}
fun main(args : Array<String>) {
// Create outer link from cyclic garbage.
val outer = Node(42, null, null, null)
createCycles(outer)
konan.internal.GC.collect()
// Ensure outer is not collected.
println(outer.data)
}