JVM_IR: Unbox inline classes in suspend functions
if the function can be verified to safely returning unboxed inline class. Box the return value on resume path.
This commit is contained in:
+1
-1
@@ -491,7 +491,7 @@ fun InstructionAdapter.loadCoroutineSuspendedMarker(languageVersionSettings: Lan
|
||||
)
|
||||
}
|
||||
|
||||
internal fun InstructionAdapter.generateCoroutineSuspendedCheck(languageVersionSettings: LanguageVersionSettings) {
|
||||
fun InstructionAdapter.generateCoroutineSuspendedCheck(languageVersionSettings: LanguageVersionSettings) {
|
||||
dup()
|
||||
loadCoroutineSuspendedMarker(languageVersionSettings)
|
||||
val elseLabel = Label()
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
@@ -414,17 +415,21 @@ fun addInlineMarker(v: InstructionAdapter, isStartNotEnd: Boolean) {
|
||||
internal fun addUnboxInlineClassMarkersIfNeeded(v: InstructionAdapter, descriptor: CallableDescriptor, typeMapper: KotlinTypeMapper) {
|
||||
val inlineClass = (descriptor as? FunctionDescriptor)?.originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass(typeMapper)
|
||||
if (inlineClass != null) {
|
||||
addBeforeUnboxInlineClassMarker(v)
|
||||
StackValue.unboxInlineClass(AsmTypes.OBJECT_TYPE, inlineClass, v)
|
||||
// Suspend functions always returns Any?, but the unboxing disrupts type analysis of the bytecode.
|
||||
// For example, if the underlying type is String, CHECKCAST String is removed.
|
||||
// However, the unboxing is moved to the resume path, the direct path still has Any?, but now, without the CHECKCAST.
|
||||
// Thus, we add CHECKCAST Object, which we remove, after we copy the unboxing to the resume path.
|
||||
v.checkcast(AsmTypes.OBJECT_TYPE)
|
||||
addAfterUnboxInlineClassMarker(v)
|
||||
generateResumePathUnboxing(v, inlineClass)
|
||||
}
|
||||
}
|
||||
|
||||
fun generateResumePathUnboxing(v: InstructionAdapter, inlineClass: KotlinType) {
|
||||
addBeforeUnboxInlineClassMarker(v)
|
||||
StackValue.unboxInlineClass(AsmTypes.OBJECT_TYPE, inlineClass, v)
|
||||
// Suspend functions always returns Any?, but the unboxing disrupts type analysis of the bytecode.
|
||||
// For example, if the underlying type is String, CHECKCAST String is removed.
|
||||
// However, the unboxing is moved to the resume path, the direct path still has Any?, but now, without the CHECKCAST.
|
||||
// Thus, we add CHECKCAST Object, which we remove, after we copy the unboxing to the resume path.
|
||||
v.checkcast(AsmTypes.OBJECT_TYPE)
|
||||
addAfterUnboxInlineClassMarker(v)
|
||||
}
|
||||
|
||||
private fun addBeforeUnboxInlineClassMarker(v: InstructionAdapter) {
|
||||
v.emitInlineMarker(INLINE_MARKER_BEFORE_UNBOX_INLINE_CLASS)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user