Skip to content

Commit

Permalink
KT-43286 use JVM 1.8 intrinsics for coercible unsigned values only
Browse files Browse the repository at this point in the history
  • Loading branch information
dnpetrov committed Nov 25, 2020
1 parent 498047e commit f6abc5c
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 18 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ class JvmStandardLibraryBuiltInsLowering(val context: JvmBackendContext) : FileL

val parentClass = expression.symbol.owner.parent.fqNameForIrSerialization.asString()
val functionName = expression.symbol.owner.name.asString()
Jvm8builtInReplacements[parentClass to functionName]?.let {
return expression.replaceWithCallTo(it)
jvm8builtInReplacements[parentClass to functionName]?.let { replacement ->
return expression.replaceWithCallTo(replacement)
}

return expression
Expand All @@ -46,7 +46,7 @@ class JvmStandardLibraryBuiltInsLowering(val context: JvmBackendContext) : FileL
irFile.transformChildren(transformer, null)
}

private val Jvm8builtInReplacements = mapOf(
private val jvm8builtInReplacements = mapOf(
("kotlin.UInt" to "compareTo") to context.ir.symbols.compareUnsignedInt,
("kotlin.UInt" to "div") to context.ir.symbols.divideUnsignedInt,
("kotlin.UInt" to "rem") to context.ir.symbols.remainderUnsignedInt,
Expand All @@ -59,7 +59,8 @@ class JvmStandardLibraryBuiltInsLowering(val context: JvmBackendContext) : FileL

// Originals are so far only instance methods, and the replacements are
// statics, so we copy dispatch receivers to a value argument if needed.
private fun IrCall.replaceWithCallTo(replacement: IrSimpleFunctionSymbol) =
// If we can't coerce arguments to required types, keep original expression (see below).
private fun IrCall.replaceWithCallTo(replacement: IrSimpleFunctionSymbol): IrCall =
IrCallImpl.fromSymbolOwner(
startOffset,
endOffset,
Expand All @@ -68,23 +69,30 @@ class JvmStandardLibraryBuiltInsLowering(val context: JvmBackendContext) : FileL
).also { newCall ->
var valueArgumentOffset = 0
this.dispatchReceiver?.let {
newCall.putValueArgument(valueArgumentOffset, it.coerceTo(replacement.owner.valueParameters[valueArgumentOffset].type))
val coercedDispatchReceiver = it.coerceIfPossible(replacement.owner.valueParameters[valueArgumentOffset].type)
?: return this@replaceWithCallTo
newCall.putValueArgument(valueArgumentOffset, coercedDispatchReceiver)
valueArgumentOffset++
}
(0 until valueArgumentsCount).forEach {
newCall.putValueArgument(it + valueArgumentOffset, getValueArgument(it)!!.coerceTo(replacement.owner.valueParameters[it].type))
for (index in 0 until valueArgumentsCount) {
val coercedValueArgument = getValueArgument(index)!!.coerceIfPossible(replacement.owner.valueParameters[index].type)
?: return this@replaceWithCallTo
newCall.putValueArgument(index + valueArgumentOffset, coercedValueArgument)
}
}

private fun IrExpression.coerceTo(target: IrType): IrExpression =
IrCallImpl.fromSymbolOwner(
startOffset,
endOffset,
target,
context.ir.symbols.unsafeCoerceIntrinsic
).also { call ->
call.putTypeArgument(0, type)
call.putTypeArgument(1, target)
call.putValueArgument(0, this)
}
private fun IrExpression.coerceIfPossible(toType: IrType): IrExpression? {
// TODO maybe UnsafeCoerce could handle types with different, but coercible underlying representations.
// See KT-43286 and related tests for details.
val fromJvmType = context.typeMapper.mapType(type)
val toJvmType = context.typeMapper.mapType(toType)
return if (fromJvmType != toJvmType)
null
else
IrCallImpl.fromSymbolOwner(startOffset, endOffset, toType, context.ir.symbols.unsafeCoerceIntrinsic).also { call ->
call.putTypeArgument(0, type)
call.putTypeArgument(1, toType)
call.putValueArgument(0, this)
}
}
}
26 changes: 26 additions & 0 deletions compiler/testData/codegen/box/unsignedTypes/kt43286.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// JVM_TARGET: 1.8
// WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME

class D(val x: UInt?)

class E(val x: Any)

fun f(d: D): String {
return d.x?.let { d.x.toString() } ?: ""
}

fun g(e: E): String {
if (e.x is UInt) return e.x.toString()
return ""
}

fun box(): String {
val test1 = f(D(42u))
if (test1 != "42") throw Exception(test1)

val test2 = g(E(42u))
if (test2 != "42") throw Exception(test2)

return "OK"
}
8 changes: 8 additions & 0 deletions compiler/testData/codegen/box/unsignedTypes/kt43286a.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// JVM_TARGET: 1.8
// WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME

fun box(): String {
val x = 3UL % 2U
return if (x == 1UL) "OK" else "Fail: $x"
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit f6abc5c

Please sign in to comment.