Support plugin-defined instrinsics that can be non-typeOf operation types.

This commit is contained in:
Leonid Startsev
2022-09-13 15:08:54 +02:00
committed by Space
parent 033538161e
commit 69c00785f2
5 changed files with 89 additions and 37 deletions
@@ -127,7 +127,7 @@ class IrInlineIntrinsicsSupport(
.report(JvmBackendErrors.TYPEOF_NON_REIFIED_TYPE_PARAMETER_WITH_RECURSIVE_BOUND, typeParameterName.asString())
}
override fun rewritePluginDefinedOperationMarker(v: InstructionAdapter, stubConstNull: AbstractInsnNode, instructions: InsnList, type: IrType): Boolean {
return pluginExtensions.any { it.rewritePluginDefinedOperationMarker(v, stubConstNull, instructions, type) }
override fun rewritePluginDefinedOperationMarker(v: InstructionAdapter, reifiedInsn: AbstractInsnNode, instructions: InsnList, type: IrType): Boolean {
return pluginExtensions.any { it.rewritePluginDefinedOperationMarker(v, reifiedInsn, instructions, type) }
}
}
@@ -14,17 +14,45 @@ import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.org.objectweb.asm.tree.InsnList
interface JvmIrIntrinsicExtension : IrIntrinsicExtension {
/**
* Returns [IntrinsicMethod] that should emit specific bytecode instead of a regular bytecode for calling [symbol],
* or `null` if [symbol]'s call should not be replaced.
*/
fun getIntrinsic(symbol: IrFunctionSymbol): IntrinsicMethod?
/**
* Should return `true` if marker was processed.
* If this method returns `false`, a regular `TYPE_OF` intrinsic would be inserted.
* Allows to process plugin-defined reified operation marker.
* Reified operation marker is an INVOKESTATIC call to IntrinsicsSupport.reifiedOperationMarker(operationType, typeVariableName) followed
* by actual operation to be reified.
* For marker to be determined as plugin-defined, another special call should be inserted directly afterwards the operation.
* This call is MagicApiIntrinsics.voidMagicApiCall(object). Object should be a string loaded by LDC instruction. Contents of the string is plugin-defined
* and recommended way to pass data to a plugin.
*
* This is plugin's responsibility to remove any calls to MagicApiIntrinsics.voidMagicApiCall and its arguments.
* This function must return `true` if marker was processed.
* If this method returns `false`, other plugins would be queried, and if others also return `false`, a regular intrinsic determined by operationType would be inserted.
*
* If marker was processed, this is plugin's responsibility to remove any calls to MagicApiIntrinsics.voidMagicApiCall and its arguments.
*
* Example of plugin-defined reified operation marker:
*
* ```
* iconst(6) // operationType=6
* aconst(T) // typeParamName=T
* invokestatic(kotlin/jvm/internal/Intrinsics.reifiedOperationMarker)
* aconst(null) // This is operation to be reified. In case of operationType=6, this is typeOf<T>().
* // A KType instance would normally be generated on stack instead of null.
* aconst("pluginDataString") // arbitrary constant string
* invokestatic(kotlin/jvm/internal/MagicApiIntrinsics.voidMagicApiCall(Ljava/lang/Object;)V) // plugin marker call
* ```
*
* Such approach with two markers was chosen mainly for compatibility reasons:
* Call to voidMagicApiCall should be inserted directly after operationType-specific instruction (aconst(null) in the example with typeOf).
* If we form bytecode this way, old compilers would be able to correctly inline normal reified operation here, even if they do not know anything about plugin reifications.
* They won't remove invokestatic(voidMagicApiCall), but it is not a problem, since kotlin-stdlib has this function, and it is a no-op.
*/
fun rewritePluginDefinedOperationMarker(
v: InstructionAdapter,
stubConstNull: AbstractInsnNode,
reifiedInsn: AbstractInsnNode,
instructions: InsnList,
type: IrType
): Boolean