[JS IR] [Wasm] Extract InlineClassesUtils into CommonBackendContext

This commit is contained in:
Sergej Jaskiewicz
2021-12-09 14:18:48 +03:00
committed by Space
parent 962ca40687
commit e5993ab594
4 changed files with 82 additions and 39 deletions
@@ -11,6 +11,8 @@ import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irString
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrCall
@@ -19,6 +21,9 @@ import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFileSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
interface LoggingContext {
var inVerbosePhase: Boolean
@@ -67,4 +72,34 @@ interface CommonBackendContext : BackendContext, LoggingContext {
val optimizeNullChecksUsingKotlinNullability: Boolean
get() = true
/**
* See [InlineClassesUtils].
*/
val inlineClassesUtils: InlineClassesUtils
get() = DefaultInlineClassesUtils
}
/**
* Provides means for determining if a class should be treated as an inline/value class.
*
* In certain cases (for compatibility reasons) we don't want to mark a class as `inline`, but still want to treat it as one.
*
* See [org.jetbrains.kotlin.ir.backend.js.utils.JsInlineClassesUtils].
*/
interface InlineClassesUtils {
/**
* Should this class be treated as inline class?
*/
fun isClassInlineLike(klass: IrClass): Boolean = klass.isInline
/**
* Unlike [org.jetbrains.kotlin.ir.util.getInlineClassUnderlyingType], doesn't use [IrClass.inlineClassRepresentation] because
* for some reason it can be called for classes which are not inline, e.g. `kotlin.Double`.
*/
fun getInlineClassUnderlyingType(irClass: IrClass): IrType =
irClass.declarations.firstIsInstanceOrNull<IrConstructor>()?.takeIf { it.isPrimary }?.valueParameters?.get(0)?.type
?: error("Class has no primary constructor: ${irClass.fqNameWhenAvailable}")
}
object DefaultInlineClassesUtils : InlineClassesUtils
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.InlineClassesUtils
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.common.ir.isOverridableOrOverrides
import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -16,9 +17,7 @@ import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.backend.js.utils.isDispatchReceiver
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrDynamicType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.getPropertyGetter
@@ -32,7 +31,7 @@ interface JsCommonBackendContext : CommonBackendContext {
val reflectionSymbols: ReflectionSymbols
val inlineClassesUtils: InlineClassesUtils
override val inlineClassesUtils: JsCommonInlineClassesUtils
val coroutineSymbols: JsCommonCoroutineSymbols
@@ -123,8 +122,16 @@ fun findClass(memberScope: MemberScope, name: Name): ClassDescriptor =
fun findFunctions(memberScope: MemberScope, name: Name): List<SimpleFunctionDescriptor> =
memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).toList()
interface InlineClassesUtils {
fun isTypeInlined(type: IrType): Boolean
interface JsCommonInlineClassesUtils : InlineClassesUtils {
/**
* Returns the inlined class for the given type, or `null` if the type is not inlined.
*/
fun getInlinedClass(type: IrType): IrClass?
fun isTypeInlined(type: IrType): Boolean {
return getInlinedClass(type) != null
}
fun shouldValueParameterBeBoxed(parameter: IrValueParameter): Boolean {
val function = parameter.parent as? IrSimpleFunction ?: return false
@@ -133,10 +140,13 @@ interface InlineClassesUtils {
return parameter.isDispatchReceiver && function.isOverridableOrOverrides
}
fun getInlinedClass(type: IrType): IrClass?
fun isClassInlineLike(klass: IrClass): Boolean
/**
* An intrinsic for creating an instance of an inline class from its underlying value.
*/
val boxIntrinsic: IrSimpleFunctionSymbol
/**
* An intrinsic for obtaining the underlying value from an instance of an inline class.
*/
val unboxIntrinsic: IrSimpleFunctionSymbol
}
@@ -5,23 +5,39 @@
package org.jetbrains.kotlin.ir.backend.js.utils
import org.jetbrains.kotlin.ir.backend.js.InlineClassesUtils
import org.jetbrains.kotlin.ir.backend.js.JsCommonInlineClassesUtils
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isMarkedNullable
import org.jetbrains.kotlin.ir.util.getInlineClassUnderlyingType
class JsInlineClassesUtils(val context: JsIrBackendContext) : InlineClassesUtils {
override fun isTypeInlined(type: IrType): Boolean {
return getInlinedClass(type) != null
class JsInlineClassesUtils(val context: JsIrBackendContext) : JsCommonInlineClassesUtils {
override fun getInlinedClass(type: IrType): IrClass? {
if (type is IrSimpleType) {
val erased = erase(type) ?: return null
if (isClassInlineLike(erased)) {
if (type.isMarkedNullable()) {
var fieldType: IrType
var fieldInlinedClass = erased
while (true) {
fieldType = getInlineClassUnderlyingType(fieldInlinedClass)
if (fieldType.isMarkedNullable()) {
return null
}
fieldInlinedClass = getInlinedClass(fieldType) ?: break
}
}
return erased
}
}
return null
}
override fun getInlinedClass(type: IrType): IrClass? =
type.getJsInlinedClass()
override fun isClassInlineLike(klass: IrClass): Boolean =
klass.isInline
@@ -30,4 +46,4 @@ class JsInlineClassesUtils(val context: JsIrBackendContext) : InlineClassesUtils
override val unboxIntrinsic: IrSimpleFunctionSymbol
get() = context.intrinsics.jsUnboxIntrinsic
}
}
@@ -6,20 +6,15 @@
package org.jetbrains.kotlin.backend.wasm.utils
import org.jetbrains.kotlin.backend.wasm.WasmSymbols
import org.jetbrains.kotlin.ir.backend.js.InlineClassesUtils
import org.jetbrains.kotlin.ir.backend.js.JsCommonInlineClassesUtils
import org.jetbrains.kotlin.ir.backend.js.utils.erase
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isNullable
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
class WasmInlineClassesUtils(private val wasmSymbols: WasmSymbols) : InlineClassesUtils {
override fun isTypeInlined(type: IrType): Boolean {
return getInlinedClass(type) != null
}
class WasmInlineClassesUtils(private val wasmSymbols: WasmSymbols) : JsCommonInlineClassesUtils {
override fun getInlinedClass(type: IrType): IrClass? {
if (type is IrSimpleType) {
@@ -36,7 +31,7 @@ class WasmInlineClassesUtils(private val wasmSymbols: WasmSymbols) : InlineClass
override fun isClassInlineLike(klass: IrClass): Boolean {
// TODO: This hook is called from autoboxing lowering so we also handle autoboxing annotation here. In the future it's better
// to separate autoboxing from the inline class handling.
return klass.isInline || klass.hasWasmAutoboxedAnnotation()
return super.isClassInlineLike(klass) || klass.hasWasmAutoboxedAnnotation()
}
override val boxIntrinsic: IrSimpleFunctionSymbol
@@ -44,17 +39,4 @@ class WasmInlineClassesUtils(private val wasmSymbols: WasmSymbols) : InlineClass
override val unboxIntrinsic: IrSimpleFunctionSymbol
get() = wasmSymbols.unboxIntrinsic
/**
* Unlike [org.jetbrains.kotlin.ir.util.getInlineClassUnderlyingType], doesn't use [IrClass.inlineClassRepresentation] because
* for some reason it can be called for classes which are not inline, e.g. `kotlin.Double`.
*/
fun getInlineClassUnderlyingType(irClass: IrClass): IrType {
for (declaration in irClass.declarations) {
if (declaration is IrConstructor && declaration.isPrimary) {
return declaration.valueParameters[0].type
}
}
error("Class has no primary constructor: ${irClass.fqNameWhenAvailable}")
}
}