[JS IR] [Wasm] Extract InlineClassesUtils into CommonBackendContext
This commit is contained in:
+35
@@ -11,6 +11,8 @@ import org.jetbrains.kotlin.ir.IrElement
|
|||||||
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
||||||
import org.jetbrains.kotlin.ir.builders.irCall
|
import org.jetbrains.kotlin.ir.builders.irCall
|
||||||
import org.jetbrains.kotlin.ir.builders.irString
|
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.IrDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
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.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFileSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFileSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
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 {
|
interface LoggingContext {
|
||||||
var inVerbosePhase: Boolean
|
var inVerbosePhase: Boolean
|
||||||
@@ -67,4 +72,34 @@ interface CommonBackendContext : BackendContext, LoggingContext {
|
|||||||
|
|
||||||
val optimizeNullChecksUsingKotlinNullability: Boolean
|
val optimizeNullChecksUsingKotlinNullability: Boolean
|
||||||
get() = true
|
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
|
||||||
|
|||||||
+19
-9
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.BackendContext
|
import org.jetbrains.kotlin.backend.common.BackendContext
|
||||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
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.atMostOne
|
||||||
import org.jetbrains.kotlin.backend.common.ir.isOverridableOrOverrides
|
import org.jetbrains.kotlin.backend.common.ir.isOverridableOrOverrides
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
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.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.isDispatchReceiver
|
import org.jetbrains.kotlin.ir.backend.js.utils.isDispatchReceiver
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
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.symbols.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.IrDynamicType
|
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||||
import org.jetbrains.kotlin.ir.util.getPropertyGetter
|
import org.jetbrains.kotlin.ir.util.getPropertyGetter
|
||||||
@@ -32,7 +31,7 @@ interface JsCommonBackendContext : CommonBackendContext {
|
|||||||
|
|
||||||
val reflectionSymbols: ReflectionSymbols
|
val reflectionSymbols: ReflectionSymbols
|
||||||
|
|
||||||
val inlineClassesUtils: InlineClassesUtils
|
override val inlineClassesUtils: JsCommonInlineClassesUtils
|
||||||
|
|
||||||
val coroutineSymbols: JsCommonCoroutineSymbols
|
val coroutineSymbols: JsCommonCoroutineSymbols
|
||||||
|
|
||||||
@@ -123,8 +122,16 @@ fun findClass(memberScope: MemberScope, name: Name): ClassDescriptor =
|
|||||||
fun findFunctions(memberScope: MemberScope, name: Name): List<SimpleFunctionDescriptor> =
|
fun findFunctions(memberScope: MemberScope, name: Name): List<SimpleFunctionDescriptor> =
|
||||||
memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).toList()
|
memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).toList()
|
||||||
|
|
||||||
interface InlineClassesUtils {
|
interface JsCommonInlineClassesUtils : InlineClassesUtils {
|
||||||
fun isTypeInlined(type: IrType): Boolean
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
fun shouldValueParameterBeBoxed(parameter: IrValueParameter): Boolean {
|
||||||
val function = parameter.parent as? IrSimpleFunction ?: return false
|
val function = parameter.parent as? IrSimpleFunction ?: return false
|
||||||
@@ -133,10 +140,13 @@ interface InlineClassesUtils {
|
|||||||
return parameter.isDispatchReceiver && function.isOverridableOrOverrides
|
return parameter.isDispatchReceiver && function.isOverridableOrOverrides
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getInlinedClass(type: IrType): IrClass?
|
/**
|
||||||
|
* An intrinsic for creating an instance of an inline class from its underlying value.
|
||||||
fun isClassInlineLike(klass: IrClass): Boolean
|
*/
|
||||||
|
|
||||||
val boxIntrinsic: IrSimpleFunctionSymbol
|
val boxIntrinsic: IrSimpleFunctionSymbol
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An intrinsic for obtaining the underlying value from an instance of an inline class.
|
||||||
|
*/
|
||||||
val unboxIntrinsic: IrSimpleFunctionSymbol
|
val unboxIntrinsic: IrSimpleFunctionSymbol
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-8
@@ -5,23 +5,39 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.utils
|
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.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.types.isMarkedNullable
|
import org.jetbrains.kotlin.ir.types.isMarkedNullable
|
||||||
import org.jetbrains.kotlin.ir.util.getInlineClassUnderlyingType
|
|
||||||
|
|
||||||
class JsInlineClassesUtils(val context: JsIrBackendContext) : InlineClassesUtils {
|
class JsInlineClassesUtils(val context: JsIrBackendContext) : JsCommonInlineClassesUtils {
|
||||||
override fun isTypeInlined(type: IrType): Boolean {
|
|
||||||
return getInlinedClass(type) != null
|
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 =
|
override fun isClassInlineLike(klass: IrClass): Boolean =
|
||||||
klass.isInline
|
klass.isInline
|
||||||
|
|
||||||
|
|||||||
+3
-21
@@ -6,20 +6,15 @@
|
|||||||
package org.jetbrains.kotlin.backend.wasm.utils
|
package org.jetbrains.kotlin.backend.wasm.utils
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.wasm.WasmSymbols
|
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.backend.js.utils.erase
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
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.symbols.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.types.isNullable
|
import org.jetbrains.kotlin.ir.types.isNullable
|
||||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
|
||||||
|
|
||||||
class WasmInlineClassesUtils(private val wasmSymbols: WasmSymbols) : InlineClassesUtils {
|
class WasmInlineClassesUtils(private val wasmSymbols: WasmSymbols) : JsCommonInlineClassesUtils {
|
||||||
override fun isTypeInlined(type: IrType): Boolean {
|
|
||||||
return getInlinedClass(type) != null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getInlinedClass(type: IrType): IrClass? {
|
override fun getInlinedClass(type: IrType): IrClass? {
|
||||||
if (type is IrSimpleType) {
|
if (type is IrSimpleType) {
|
||||||
@@ -36,7 +31,7 @@ class WasmInlineClassesUtils(private val wasmSymbols: WasmSymbols) : InlineClass
|
|||||||
override fun isClassInlineLike(klass: IrClass): Boolean {
|
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
|
// 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.
|
// to separate autoboxing from the inline class handling.
|
||||||
return klass.isInline || klass.hasWasmAutoboxedAnnotation()
|
return super.isClassInlineLike(klass) || klass.hasWasmAutoboxedAnnotation()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val boxIntrinsic: IrSimpleFunctionSymbol
|
override val boxIntrinsic: IrSimpleFunctionSymbol
|
||||||
@@ -44,17 +39,4 @@ class WasmInlineClassesUtils(private val wasmSymbols: WasmSymbols) : InlineClass
|
|||||||
|
|
||||||
override val unboxIntrinsic: IrSimpleFunctionSymbol
|
override val unboxIntrinsic: IrSimpleFunctionSymbol
|
||||||
get() = wasmSymbols.unboxIntrinsic
|
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}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user