Introduce IrInliner

This commit is contained in:
Mikhael Bogdanov
2017-06-12 14:45:56 +02:00
parent 9f736f2192
commit 8ab705a14c
7 changed files with 357 additions and 60 deletions
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import java.util.*
class DefaultCallArgs(val size: Int) {
@@ -32,7 +31,7 @@ class DefaultCallArgs(val size: Int) {
bits.set(index)
}
private fun toInts(): List<Int> {
fun toInts(): List<Int> {
if (bits.isEmpty || size == 0) {
return emptyList()
}
@@ -64,17 +63,4 @@ class DefaultCallArgs(val size: Int) {
}
return toInts.isNotEmpty()
}
fun generateOnStackIfNeeded(iv: InstructionAdapter, isConstructor: Boolean): Boolean {
val toInts = toInts()
if (!toInts.isEmpty()) {
for (mask in toInts) {
iv.iconst(mask)
}
val parameterType = if (isConstructor) AsmTypes.DEFAULT_CONSTRUCTOR_MARKER else AsmTypes.OBJECT_TYPE
iv.aconst(null)
}
return toInts.isNotEmpty()
}
}
@@ -105,6 +105,8 @@ import java.util.*;
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isInt;
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
import static org.jetbrains.kotlin.codegen.CodegenUtilKt.extractReificationArgument;
import static org.jetbrains.kotlin.codegen.CodegenUtilKt.unwrapInitialSignatureDescriptor;
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.*;
@@ -2295,12 +2297,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
}
@NotNull
private static FunctionDescriptor unwrapInitialSignatureDescriptor(@NotNull FunctionDescriptor function) {
if (function.getInitialSignatureDescriptor() != null) return function.getInitialSignatureDescriptor();
return function;
}
@NotNull
protected CallGenerator getOrCreateCallGeneratorForDefaultImplBody(@NotNull FunctionDescriptor descriptor, @Nullable KtNamedFunction function) {
return getOrCreateCallGenerator(descriptor, function, null, true);
@@ -2370,22 +2366,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return typeArgumentsMap;
}
@Nullable
private static Pair<TypeParameterDescriptor, ReificationArgument> extractReificationArgument(@NotNull KotlinType type) {
int arrayDepth = 0;
boolean isNullable = type.isMarkedNullable();
while (KotlinBuiltIns.isArray(type)) {
arrayDepth++;
type = type.getArguments().get(0).getType();
}
TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(type);
if (parameterDescriptor == null) return null;
return new Pair<>(parameterDescriptor, new ReificationArgument(parameterDescriptor.getName().asString(), isNullable, arrayDepth));
}
@NotNull
public StackValue generateReceiverValue(@Nullable ReceiverValue receiverValue, boolean isSuper) {
if (receiverValue instanceof ImplicitClassReceiver) {
@@ -17,17 +17,20 @@
package org.jetbrains.kotlin.codegen
import com.google.common.collect.Maps
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext
import org.jetbrains.kotlin.codegen.context.PackageContext
import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction
import org.jetbrains.kotlin.codegen.inline.ReificationArgument
import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.diagnostics.rendering.Renderers
import org.jetbrains.kotlin.diagnostics.rendering.RenderingContext
@@ -44,6 +47,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils.isSubclass
import org.jetbrains.kotlin.resolve.annotations.hasJvmStaticAnnotation
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
@@ -396,3 +400,20 @@ fun InstructionAdapter.generateNewInstanceDupAndPlaceBeforeStackTop(
load(index, topStackType)
}
}
fun extractReificationArgument(type: KotlinType): Pair<TypeParameterDescriptor, ReificationArgument>? {
var type = type
var arrayDepth = 0
val isNullable = type.isMarkedNullable
while (KotlinBuiltIns.isArray(type)) {
arrayDepth++
type = type.arguments[0].type
}
val parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(type) ?: return null
return Pair(parameterDescriptor, ReificationArgument(parameterDescriptor.name.asString(), isNullable, arrayDepth))
}
fun unwrapInitialSignatureDescriptor(function: FunctionDescriptor): FunctionDescriptor =
function.initialSignatureDescriptor ?: function
@@ -22,8 +22,12 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil.*
import org.jetbrains.kotlin.codegen.StackValue.*
import org.jetbrains.kotlin.codegen.inline.NameGenerator
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages
import org.jetbrains.kotlin.codegen.inline.TypeParameterMappings
import org.jetbrains.kotlin.codegen.intrinsics.JavaClassProperty
import org.jetbrains.kotlin.codegen.pseudoInsns.fixStackAndJump
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.ir.IrElement
@@ -34,13 +38,17 @@ import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_THROWABLE_TYPE
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typesApproximation.approximateCapturedTypes
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.keysToMap
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
@@ -93,7 +101,7 @@ class ExpressionCodegen(
val frame: FrameMap,
val mv: InstructionAdapter,
val classCodegen: ClassCodegen
) : IrElementVisitor<StackValue, BlockInfo> {
) : IrElementVisitor<StackValue, BlockInfo>, BaseExpressionCodegen {
/*TODO*/
val intrinsics = IrIntrinsicMethods(classCodegen.context.irBuiltIns)
@@ -102,6 +110,8 @@ class ExpressionCodegen(
val returnType = typeMapper.mapReturnType(irFunction.descriptor)
val state = classCodegen.state
fun generate() {
mv.visitCode()
val info = BlockInfo.create()
@@ -205,44 +215,52 @@ class ExpressionCodegen(
if (callable is IrIntrinsicFunction) {
return callable.invoke(mv, this, data)
} else {
val callGenerator = getOrCreateCallGenerator(expression, expression.descriptor)
val receiver = expression.dispatchReceiver
receiver?.apply {
gen(receiver, callable.dispatchReceiverType!!, data)
//gen(receiver, callable.dispatchReceiverType!!, data)
callGenerator.genValueAndPut(null, this, callable.dispatchReceiverType!!, -1, this@ExpressionCodegen, data)
}
expression.extensionReceiver?.apply {
gen(this, callable.extensionReceiverType!!, data)
//gen(this, callable.extensionReceiverType!!, data)
callGenerator.genValueAndPut(null, this, callable.extensionReceiverType!!, -1, this@ExpressionCodegen, data)
}
val args = expression.descriptor.valueParameters.mapIndexed { i, valueParameterDescriptor ->
expression.getValueArgument(i) ?:
if (valueParameterDescriptor.hasDefaultValue()) DefaultArg(i) else Vararg(i)
}
val defaultMask = DefaultCallArgs(callable.valueParameterTypes.size)
args.forEachIndexed { i, expression ->
when (expression) {
is IrExpression -> {
gen(expression, callable.valueParameterTypes[i], data)
expression.descriptor.valueParameters.forEachIndexed { i, parameterDescriptor ->
val arg = expression.getValueArgument(i)
val parameterType = callable.valueParameterTypes[i]
when {
arg != null -> {
callGenerator.genValueAndPut(parameterDescriptor, arg, parameterType, i, this@ExpressionCodegen, data)
}
is DefaultArg -> {
pushDefaultValueOnStack(callable.valueParameterTypes[i], mv)
defaultMask.mark(expression.index)
parameterDescriptor.hasDefaultValue() -> {
callGenerator.putValueIfNeeded(parameterType, StackValue.createDefaulValue(parameterType), ValueKind.DEFAULT_PARAMETER, i, this@ExpressionCodegen)
defaultMask.mark(i)
}
is Vararg -> {
mv.aconst(null)
else -> {
assert(parameterDescriptor.varargElementType != null)
//empty vararg
callGenerator.putValueIfNeeded(
parameterType,
StackValue.operation(parameterType) {
it.aconst(0)
it.newarray(correctElementType(parameterType))
},
ValueKind.GENERAL_VARARG, i, this@ExpressionCodegen)
}
else -> TODO()
}
}
callGenerator.genCall(
callable,
defaultMask.generateOnStackIfNeeded(callGenerator, expression.descriptor is ConstructorDescriptor, this),
this
)
if (!defaultMask.generateOnStackIfNeeded(mv, expression.descriptor is ConstructorDescriptor)) {
callable.genInvokeInstruction(mv)
} else {
(callable as CallableMethod).genInvokeDefaultInstruction(mv)
}
val returnType = expression.descriptor.returnType
if (returnType != null && KotlinBuiltIns.isNothing(returnType)) {
mv.aconst(null)
@@ -897,8 +915,102 @@ class ExpressionCodegen(
private val CallableDescriptor.asmType: Type
get() = typeMapper.mapType(this)
private fun getOrCreateCallGenerator(
descriptor: CallableDescriptor,
element: IrMemberAccessExpression?,
typeParameterMappings: TypeParameterMappings?,
isDefaultCompilation: Boolean
): IrCallGenerator {
if (element == null) return IrCallGenerator.DefaultCallGenerator
// We should inline callable containing reified type parameters even if inline is disabled
// because they may contain something to reify and straight call will probably fail at runtime
val isInline = (!state.isInlineDisabled || InlineUtil.containsReifiedTypeParameters(descriptor)) && (InlineUtil.isInline(descriptor) || InlineUtil.isArrayConstructorWithLambda(descriptor))
if (!isInline) return IrCallGenerator.DefaultCallGenerator
val original = unwrapInitialSignatureDescriptor(DescriptorUtils.unwrapFakeOverride(descriptor.original as FunctionDescriptor))
if (isDefaultCompilation) {
return TODO()
}
else {
return IrInlineCodegen(this, state, original, typeParameterMappings!!, IrSourceCompilerForInline(state, element))
}
}
internal fun getOrCreateCallGenerator(memberAccessExpression: IrMemberAccessExpression, descriptor: CallableDescriptor): IrCallGenerator {
val typeArguments = descriptor.typeParameters.keysToMap { memberAccessExpression.getTypeArgumentOrDefault(it) }
val mappings = TypeParameterMappings()
for (entry in typeArguments.entries) {
val key = entry.key
val type = entry.value
val isReified = key.isReified || InlineUtil.isArrayConstructorWithLambda(descriptor)
val typeParameterAndReificationArgument = extractReificationArgument(type)
if (typeParameterAndReificationArgument == null) {
val approximatedType = approximateCapturedTypes(entry.value).upper
// type is not generic
val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.TYPE)
val asmType = typeMapper.mapTypeParameter(approximatedType, signatureWriter)
mappings.addParameterMappingToType(
key.name.identifier, approximatedType, asmType, signatureWriter.toString(), isReified
)
}
else {
mappings.addParameterMappingForFurtherReification(
key.name.identifier, type, typeParameterAndReificationArgument.second, isReified
)
}
}
return getOrCreateCallGenerator(descriptor, memberAccessExpression, mappings, false)
}
override val frameMap: FrameMap
get() = frame
override val visitor: InstructionAdapter
get() = mv
override val inlineNameGenerator: NameGenerator = NameGenerator("${classCodegen.type.internalName}\$todo")
override val lastLineNumber: Int
get() = -1 //TODO
override fun consumeReifiedOperationMarker(typeParameterDescriptor: TypeParameterDescriptor) {
//TODO
}
override fun propagateChildReifiedTypeParametersUsages(reifiedTypeParametersUsages: ReifiedTypeParametersUsages) {
//TODO
}
override fun pushClosureOnStack(classDescriptor: ClassDescriptor, putThis: Boolean, callGenerator: CallGenerator, functionReferenceReceiver: StackValue?) {
//TODO
}
override fun markLineNumberAfterInlineIfNeeded() {
//TODO
}
}
private class DefaultArg(val index: Int)
private class Vararg(val index: Int)
fun DefaultCallArgs.generateOnStackIfNeeded(callGenerator: IrCallGenerator, isConstructor: Boolean, codegen: ExpressionCodegen): Boolean {
val toInts = toInts()
if (!toInts.isEmpty()) {
for (mask in toInts) {
callGenerator.putValueIfNeeded(Type.INT_TYPE, StackValue.constant(mask, Type.INT_TYPE), ValueKind.DEFAULT_MASK, -1, codegen)
}
val parameterType = if (isConstructor) AsmTypes.DEFAULT_CONSTRUCTOR_MARKER else AsmTypes.OBJECT_TYPE
callGenerator.putValueIfNeeded(parameterType, StackValue.constant(null, parameterType), ValueKind.METHOD_HANDLE_IN_DEFAULT, -1, codegen)
}
return toInts.isNotEmpty()
}
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2017 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.jvm.codegen
import org.jetbrains.kotlin.codegen.Callable
import org.jetbrains.kotlin.codegen.CallableMethod
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.ValueKind
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.org.objectweb.asm.Type
interface IrCallGenerator {
fun genCall(callableMethod: Callable, callDefault: Boolean, codegen: ExpressionCodegen) {
if (!callDefault) {
callableMethod.genInvokeInstruction(codegen.mv)
} else {
(callableMethod as CallableMethod).genInvokeDefaultInstruction(codegen.mv)
}
}
fun genValueAndPut(
valueParameterDescriptor: ValueParameterDescriptor?,
argumentExpression: IrExpression,
parameterType: Type,
parameterIndex: Int,
codegen: ExpressionCodegen,
blockInfo: BlockInfo) {
codegen.gen(argumentExpression, parameterType, blockInfo)
}
fun putValueIfNeeded(parameterType: Type, value: StackValue, kind: ValueKind, parameterIndex: Int, codegen: ExpressionCodegen) {
value.put(parameterType, codegen.visitor)
}
object DefaultCallGenerator: IrCallGenerator {
}
}
@@ -0,0 +1,47 @@
/*
* Copyright 2010-2017 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.jvm.codegen
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.inline.*
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.expressions.IrBlock
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.org.objectweb.asm.Type
class IrInlineCodegen(
codegen: ExpressionCodegen,
state: GenerationState,
function: FunctionDescriptor,
typeParameterMappings: TypeParameterMappings,
sourceCompiler: SourceCompilerForInline
) : InlineCodegen<ExpressionCodegen>(codegen, state, function, typeParameterMappings, sourceCompiler), IrCallGenerator {
override fun putClosureParametersOnStack(next: LambdaInfo, functionReferenceReceiver: StackValue?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun genValueAndPut(valueParameterDescriptor: ValueParameterDescriptor?, argumentExpression: IrExpression, parameterType: Type, parameterIndex: Int, codegen: ExpressionCodegen, blockInfo: BlockInfo) {
if (argumentExpression is IrBlock && argumentExpression.origin == IrStatementOrigin.LAMBDA) {
//TODO
}
super.genValueAndPut(valueParameterDescriptor, argumentExpression, parameterType, parameterIndex, codegen, blockInfo)
}
}
@@ -0,0 +1,96 @@
/*
* Copyright 2010-2017 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.jvm.codegen
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.SourceInfo
import org.jetbrains.kotlin.codegen.inline.*
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.commons.Method
import org.jetbrains.org.objectweb.asm.tree.MethodNode
class IrSourceCompilerForInline(
override val state: GenerationState,
override val callElement: IrMemberAccessExpression
): SourceCompilerForInline {
//TODO
override val lookupLocation: LookupLocation
get() = NoLookupLocation.FROM_BACKEND
//TODO
override val callElementText: String
get() = callElement.toString()
override val callsiteFile: PsiFile?
get() = TODO("not implemented")
override val contextKind: OwnerKind
get() = OwnerKind.getMemberOwnerKind(callElement.descriptor.containingDeclaration)
override val inlineCallSiteInfo: InlineCallSiteInfo
get() = InlineCallSiteInfo("TODO", null, null)
override val lazySourceMapper: DefaultSourceMapper
get() = DefaultSourceMapper(SourceInfo("TODO", "TODO", 100))
override fun generateLambdaBody(adapter: MethodVisitor, jvmMethodSignature: JvmMethodSignature, lambdaInfo: ExpressionLambda): SMAP {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun doCreateMethodNodeFromSource(callableDescriptor: FunctionDescriptor, jvmSignature: JvmMethodSignature, callDefault: Boolean, asmMethod: Method): SMAPAndMethodNode {
TODO("not implemented")
}
override fun generateAndInsertFinallyBlocks(intoNode: MethodNode, insertPoints: List<MethodInliner.PointForExternalFinallyBlocks>, offsetForFinallyLocalVar: Int) {
//TODO("not implemented")
}
override fun isCallInsideSameModuleAsDeclared(functionDescriptor: FunctionDescriptor): Boolean {
//TODO("not implemented")
return true
}
override fun isFinallyMarkerRequired(): Boolean {
//TODO("not implemented")
return false
}
override val compilationContextDescriptor: DeclarationDescriptor
get() = callElement.descriptor
override val compilationContextFunctionDescriptor: FunctionDescriptor
get() = callElement.descriptor as FunctionDescriptor
override fun getContextLabels(): Set<String> {
//TODO
return emptySet()
}
override fun initializeInlineFunctionContext(functionDescriptor: FunctionDescriptor) {
//TODO
}
}