Skip to content

Commit d41d09f

Browse files
Alexey AndreevAlexey Andreev
authored andcommitted
JS: add metadata for generated continuation classes to properly implement RTTI
1 parent 6860b2c commit d41d09f

File tree

6 files changed

+74
-7
lines changed

6 files changed

+74
-7
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// WITH_RUNTIME
2+
// WITH_REFLECT
3+
4+
class Controller {
5+
suspend fun runInstanceOf(x: Continuation<Boolean>) {
6+
val y: Any = x
7+
x.resume(x is Continuation<*>)
8+
}
9+
10+
suspend fun runCast(x: Continuation<Boolean>) {
11+
val y: Any = x
12+
x.resume(Continuation::class.isInstance(y as Continuation<*>))
13+
}
14+
}
15+
16+
fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
17+
c(Controller()).resume(Unit)
18+
}
19+
20+
fun box(): String {
21+
var result = ""
22+
23+
builder {
24+
result = runInstanceOf().toString() + "," + runCast().toString()
25+
}
26+
27+
if (result != "true,true") return "fail: $result"
28+
29+
return "OK"
30+
}

compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4520,6 +4520,12 @@ public void testInnerSuspensionCalls() throws Exception {
45204520
doTest(fileName);
45214521
}
45224522

4523+
@TestMetadata("instanceOfContinuation.kt")
4524+
public void testInstanceOfContinuation() throws Exception {
4525+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/instanceOfContinuation.kt");
4526+
doTest(fileName);
4527+
}
4528+
45234529
@TestMetadata("iterateOverArray.kt")
45244530
public void testIterateOverArray() throws Exception {
45254531
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/iterateOverArray.kt");

compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4520,6 +4520,12 @@ public void testInnerSuspensionCalls() throws Exception {
45204520
doTest(fileName);
45214521
}
45224522

4523+
@TestMetadata("instanceOfContinuation.kt")
4524+
public void testInstanceOfContinuation() throws Exception {
4525+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/instanceOfContinuation.kt");
4526+
doTest(fileName);
4527+
}
4528+
45234529
@TestMetadata("iterateOverArray.kt")
45244530
public void testIterateOverArray() throws Exception {
45254531
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/iterateOverArray.kt");

js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/metadata/metadataProperties.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ var JsNameRef.coroutineResult by MetadataProperty(default = false)
9797
*/
9898
var JsNameRef.coroutineController by MetadataProperty(default = false)
9999

100+
var JsFunction.continuationInterfaceRef: JsExpression? by MetadataProperty(default = null)
101+
100102
enum class TypeCheck {
101103
TYPEOF,
102104
INSTANCEOF,

js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineFunctionTransformer.kt

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,7 @@
1717
package org.jetbrains.kotlin.js.coroutine
1818

1919
import com.google.dart.compiler.backend.js.ast.*
20-
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind
21-
import com.google.dart.compiler.backend.js.ast.metadata.coroutineController
22-
import com.google.dart.compiler.backend.js.ast.metadata.coroutineResult
23-
import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
20+
import com.google.dart.compiler.backend.js.ast.metadata.*
2421
import org.jetbrains.kotlin.descriptors.ClassDescriptor
2522
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
2623
import org.jetbrains.kotlin.js.inline.clean.FunctionPostProcessor
@@ -70,7 +67,7 @@ class CoroutineFunctionTransformer(
7067
return additionalStatements
7168
}
7269

73-
private fun generateContinuationConstructor(bodyTransformer: CoroutineBodyTransformer,statements: MutableList<JsStatement>) {
70+
private fun generateContinuationConstructor(bodyTransformer: CoroutineBodyTransformer, statements: MutableList<JsStatement>) {
7471
val constructor = JsFunction(function.scope.parent, JsBlock(), "Continuation")
7572
constructor.name = className
7673
constructor.parameters += function.parameters.map { JsParameter(it.name) }
@@ -96,7 +93,21 @@ class CoroutineFunctionTransformer(
9693
}
9794
}
9895

99-
statements.add(0, constructor.makeStmt())
96+
statements.addAll(0, listOf(constructor.makeStmt(), generateCoroutineMetadata(constructor.name)))
97+
}
98+
99+
private fun generateCoroutineMetadata(constructorName: JsName): JsStatement {
100+
val interfaceRef = function.continuationInterfaceRef!!.deepCopy()
101+
102+
val metadataObject = JsObjectLiteral(true)
103+
metadataObject.propertyInitializers += JsPropertyInitializer(
104+
JsNameRef("type"), JsNameRef("CLASS", JsNameRef("TYPE", Namer.KOTLIN_NAME)))
105+
metadataObject.propertyInitializers += JsPropertyInitializer(
106+
JsNameRef("classIndex"), JsInvocation(JsNameRef("newClassIndex", Namer.KOTLIN_NAME)))
107+
metadataObject.propertyInitializers += JsPropertyInitializer(JsNameRef("simpleName"), JsLiteral.NULL)
108+
metadataObject.propertyInitializers += JsPropertyInitializer(JsNameRef("baseClasses"), JsArrayLiteral(listOf(interfaceRef)))
109+
110+
return JsAstUtils.assignment(JsNameRef(Namer.METADATA, constructorName.makeRef()), metadataObject).makeStmt()
100111
}
101112

102113
private fun generateContinuationMethods(doResumeName: JsName, statements: MutableList<JsStatement>) {

js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/LiteralFunctionTranslator.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ package org.jetbrains.kotlin.js.translate.expression
1818

1919
import com.google.dart.compiler.backend.js.ast.*
2020
import com.google.dart.compiler.backend.js.ast.metadata.*
21+
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
2122
import org.jetbrains.kotlin.descriptors.*
22-
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
2323
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
2424
import org.jetbrains.kotlin.js.descriptorUtils.isCoroutineLambda
2525
import org.jetbrains.kotlin.js.inline.util.getInnerFunction
@@ -28,14 +28,18 @@ import org.jetbrains.kotlin.js.translate.context.getNameForCapturedDescriptor
2828
import org.jetbrains.kotlin.js.translate.context.hasCapturedExceptContaining
2929
import org.jetbrains.kotlin.js.translate.context.isCaptured
3030
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
31+
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
3132
import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getFunctionDescriptor
3233
import org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator.translateFunctionBody
3334
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
3435
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.simpleReturnFunction
36+
import org.jetbrains.kotlin.name.ClassId
37+
import org.jetbrains.kotlin.name.Name
3538
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
3639
import org.jetbrains.kotlin.psi.KtParameter
3740
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
3841
import org.jetbrains.kotlin.resolve.inline.InlineUtil
42+
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
3943

4044
class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslator(context) {
4145
fun translate(
@@ -81,6 +85,7 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
8185
lambda.name = null
8286
}
8387
lambdaCreator.name.staticRef = lambdaCreator
88+
lambdaCreator.continuationInterfaceRef = invokingContext.getContinuationInterfaceReference()
8489
return lambdaCreator.withCapturedParameters(descriptor, descriptor.wrapContextForCoroutineIfNecessary(functionContext),
8590
invokingContext)
8691
}
@@ -91,6 +96,7 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
9196

9297
invokingContext.addDeclarationStatement(lambda.makeStmt())
9398
lambda.name.staticRef = lambda
99+
lambda.continuationInterfaceRef = invokingContext.getContinuationInterfaceReference()
94100
return getReferenceToLambda(invokingContext, descriptor, lambda.name)
95101
}
96102

@@ -104,6 +110,12 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
104110
}
105111
}
106112

113+
private fun TranslationContext.getContinuationInterfaceReference(): JsExpression {
114+
val coroutineClassId = ClassId.topLevel(KotlinBuiltIns.COROUTINES_PACKAGE_FQ_NAME.child(Name.identifier("Continuation")))
115+
val classDescriptor = currentModule.findClassAcrossModuleDependencies(coroutineClassId)!!
116+
return ReferenceTranslator.translateAsTypeReference(classDescriptor, this)
117+
}
118+
107119
private fun CallableMemberDescriptor.wrapContextForCoroutineIfNecessary(context: TranslationContext): TranslationContext {
108120
return if (isCoroutineLambda) context.innerContextWithDescriptorsAliased(mapOf(this to JsLiteral.THIS)) else context
109121
}

0 commit comments

Comments
 (0)