Use java.lang.Long.divideUnsigned/remainderUnsigned in Java 1.8+

#KT-24876
This commit is contained in:
Dmitry Petrov
2019-01-11 17:32:12 +03:00
parent a344feff5c
commit 9973d59643
19 changed files with 361 additions and 2 deletions
@@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.codegen.Callable;
import org.jetbrains.kotlin.codegen.CallableMethod;
import org.jetbrains.kotlin.codegen.ExpressionCodegen;
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
@@ -36,6 +37,10 @@ public abstract class IntrinsicMethod {
return toCallable(codegen.getState().getTypeMapper().mapToCallableMethod(fd, false), isSuper, resolvedCall);
}
public boolean isApplicableToOverload(@NotNull CallableMemberDescriptor descriptor) {
return true;
}
@NotNull
protected Callable toCallable(@NotNull CallableMethod method, boolean isSuper, @NotNull ResolvedCall resolvedCall) {
return toCallable(method, isSuper);
@@ -41,6 +41,8 @@ public class IntrinsicMethods {
private static final FqName KOTLIN_JVM = new FqName("kotlin.jvm");
/* package */ static final FqNameUnsafe RECEIVER_PARAMETER_FQ_NAME = new FqNameUnsafe("T");
private static final FqNameUnsafe KOTLIN_ULONG = new FqNameUnsafe("kotlin.ULong");
private static final IntrinsicMethod UNARY_MINUS = new UnaryMinus();
private static final IntrinsicMethod UNARY_PLUS = new UnaryPlus();
private static final IntrinsicMethod NUMBER_CAST = new NumberCast();
@@ -153,6 +155,16 @@ public class IntrinsicMethods {
}
declareArrayMethods();
if (jvmTarget.compareTo(JvmTarget.JVM_1_8) >= 0) {
Java8ULongDivide java8ULongDivide = new Java8ULongDivide();
Java8ULongRemainder java8ULongRemainder = new Java8ULongRemainder();
intrinsicsMap.registerIntrinsic(KOTLIN_ULONG.toSafe(), null, "div", 1, java8ULongDivide);
intrinsicsMap.registerIntrinsic(KOTLIN_ULONG.toSafe(), null, "rem", 1, java8ULongRemainder);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, null, "ulongDivide", 2, java8ULongDivide);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, null, "ulongRemainder", 2, java8ULongRemainder);
}
}
private void declareArrayMethods() {
@@ -56,12 +56,15 @@ internal class IntrinsicsMap {
}
fun getIntrinsic(descriptor: CallableMemberDescriptor): IntrinsicMethod? =
intrinsicsMap[Key(
intrinsicsMap[getKey(descriptor)]?.takeIf { it.isApplicableToOverload(descriptor.original) }
private fun getKey(descriptor: CallableMemberDescriptor): Key =
Key(
DescriptorUtils.getFqName(descriptor.containingDeclaration),
getReceiverParameterFqName(descriptor),
descriptor.name.asString(),
valueParameterCountForKey(descriptor)
)]
)
private fun getReceiverParameterFqName(descriptor: CallableMemberDescriptor): FqNameUnsafe? {
val receiverParameter = descriptor.extensionReceiverParameter ?: return null
@@ -72,4 +75,6 @@ internal class IntrinsicsMap {
else
DescriptorUtils.getFqName(classifier)
}
}
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.intrinsics
import org.jetbrains.kotlin.codegen.Callable
import org.jetbrains.kotlin.codegen.CallableMethod
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
abstract class UnsignedLongDivisionIntrinsic : IntrinsicMethod() {
override fun isApplicableToOverload(descriptor: CallableMemberDescriptor): Boolean {
if (descriptor.containingDeclaration is PackageFragmentDescriptor) return true
val singleValueParameterTypeDescriptor = descriptor.valueParameters.single().type.constructor.declarationDescriptor
?: throw AssertionError("Unexpected descriptor for unsigned long division intrinsic: $descriptor")
return singleValueParameterTypeDescriptor.name.asString() == "ULong"
}
}
class Java8ULongDivide : UnsignedLongDivisionIntrinsic() {
override fun toCallable(method: CallableMethod): Callable =
createIntrinsicCallable(method) {
it.invokestatic("java/lang/Long", "divideUnsigned", "(JJ)J", false)
}
}
class Java8ULongRemainder : UnsignedLongDivisionIntrinsic() {
override fun toCallable(method: CallableMethod): Callable =
createIntrinsicCallable(method) {
it.invokestatic("java/lang/Long", "remainderUnsigned", "(JJ)J", false)
}
}
@@ -0,0 +1,18 @@
// JVM_TARGET: 1.6
// WITH_RUNTIME
// IGNORE_BACKEND: JVM_IR
val ua = 1234UL
val ub = 5678UL
val uai = ua.toUInt()
val u = ua * ub
fun box(): String {
val div = u / ua
if (div != ub) throw AssertionError("$div")
val divInt = u / uai
if (div != ub) throw AssertionError("$div")
return "OK"
}
@@ -0,0 +1,18 @@
// JVM_TARGET: 1.8
// WITH_RUNTIME
// IGNORE_BACKEND: JVM_IR
val ua = 1234UL
val ub = 5678UL
val uai = ua.toUInt()
val u = ua * ub
fun box(): String {
val div = u / ua
if (div != ub) throw AssertionError("$div")
val divInt = u / uai
if (div != ub) throw AssertionError("$div")
return "OK"
}
@@ -0,0 +1,15 @@
// JVM_TARGET: 1.6
// WITH_RUNTIME
// IGNORE_BACKEND: JVM_IR
val ua = 1234UL
val ub = 5678UL
val uc = 3456UL
val u = ua * ub + uc
fun box(): String {
val rem = u % ub
if (rem != uc) throw AssertionError("$rem")
return "OK"
}
@@ -0,0 +1,15 @@
// JVM_TARGET: 1.8
// WITH_RUNTIME
// IGNORE_BACKEND: JVM_IR
val ua = 1234UL
val ub = 5678UL
val uc = 3456UL
val u = ua * ub + uc
fun box(): String {
val rem = u % ub
if (rem != uc) throw AssertionError("$rem")
return "OK"
}
@@ -0,0 +1,16 @@
// JVM_TARGET: 1.6
// WITH_RUNTIME
// IGNORE_BACKEND: JVM_IR
val ua = 1234UL
val ub = 5678UL
val u = ua * ub
fun box(): String {
val div = u / ua
if (div != ub) throw AssertionError("$div")
return "OK"
}
// 1 INVOKESTATIC kotlin/UnsignedKt.ulongDivide
@@ -0,0 +1,17 @@
// JVM_TARGET: 1.8
// WITH_RUNTIME
// IGNORE_BACKEND: JVM_IR
val ua = 1234UL
val ub = 5678UL
val u = ua * ub
fun box(): String {
val div = u / ua
if (div != ub) throw AssertionError("$div")
return "OK"
}
// 0 kotlin/UnsignedKt.ulongDivide
// 1 INVOKESTATIC java/lang/Long.divideUnsigned \(JJ\)J
@@ -0,0 +1,17 @@
// JVM_TARGET: 1.6
// WITH_RUNTIME
// IGNORE_BACKEND: JVM_IR
val ua = 1234UL
val ub = 5678UL
val uc = 3456UL
val u = ua * ub + uc
fun box(): String {
val rem = u % ub
if (rem != uc) throw AssertionError("$rem")
return "OK"
}
// 1 kotlin/UnsignedKt.ulongRemainder
@@ -0,0 +1,18 @@
// JVM_TARGET: 1.8
// WITH_RUNTIME
// IGNORE_BACKEND: JVM_IR
val ua = 1234UL
val ub = 5678UL
val uc = 3456UL
val u = ua * ub + uc
fun box(): String {
val rem = u % ub
if (rem != uc) throw AssertionError("$rem")
return "OK"
}
// 0 kotlin/UnsignedKt.ulongRemainder
// 1 INVOKESTATIC java/lang/Long.remainderUnsigned \(JJ\)J
@@ -24288,6 +24288,26 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLiteralsWithSignedOverflow.kt");
}
@TestMetadata("unsignedLongDivide_jvm16.kt")
public void testUnsignedLongDivide_jvm16() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongDivide_jvm16.kt");
}
@TestMetadata("unsignedLongDivide_jvm18.kt")
public void testUnsignedLongDivide_jvm18() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongDivide_jvm18.kt");
}
@TestMetadata("unsignedLongRemainder_jvm16.kt")
public void testUnsignedLongRemainder_jvm16() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongRemainder_jvm16.kt");
}
@TestMetadata("unsignedLongRemainder_jvm18.kt")
public void testUnsignedLongRemainder_jvm18() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongRemainder_jvm18.kt");
}
@TestMetadata("unsignedTypePrefixIncrementDecrementBoxing.kt")
public void testUnsignedTypePrefixIncrementDecrementBoxing() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedTypePrefixIncrementDecrementBoxing.kt");
@@ -3106,6 +3106,39 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
}
}
@TestMetadata("compiler/testData/codegen/bytecodeText/unsignedTypes")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class UnsignedTypes extends AbstractBytecodeTextTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInUnsignedTypes() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/unsignedTypes"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("unsignedLongDivide_jvm16.kt")
public void testUnsignedLongDivide_jvm16() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/unsignedTypes/unsignedLongDivide_jvm16.kt");
}
@TestMetadata("unsignedLongDivide_jvm18.kt")
public void testUnsignedLongDivide_jvm18() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/unsignedTypes/unsignedLongDivide_jvm18.kt");
}
@TestMetadata("unsignedLongRemainder_jvm16.kt")
public void testUnsignedLongRemainder_jvm16() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/unsignedTypes/unsignedLongRemainder_jvm16.kt");
}
@TestMetadata("unsignedLongRemainder_jvm18.kt")
public void testUnsignedLongRemainder_jvm18() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/unsignedTypes/unsignedLongRemainder_jvm18.kt");
}
}
@TestMetadata("compiler/testData/codegen/bytecodeText/varargs")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -3106,6 +3106,39 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
}
}
@TestMetadata("compiler/testData/codegen/bytecodeText/unsignedTypes")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class UnsignedTypes extends AbstractIrBytecodeTextTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
}
public void testAllFilesPresentInUnsignedTypes() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/unsignedTypes"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
}
@TestMetadata("unsignedLongDivide_jvm16.kt")
public void testUnsignedLongDivide_jvm16() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/unsignedTypes/unsignedLongDivide_jvm16.kt");
}
@TestMetadata("unsignedLongDivide_jvm18.kt")
public void testUnsignedLongDivide_jvm18() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/unsignedTypes/unsignedLongDivide_jvm18.kt");
}
@TestMetadata("unsignedLongRemainder_jvm16.kt")
public void testUnsignedLongRemainder_jvm16() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/unsignedTypes/unsignedLongRemainder_jvm16.kt");
}
@TestMetadata("unsignedLongRemainder_jvm18.kt")
public void testUnsignedLongRemainder_jvm18() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/unsignedTypes/unsignedLongRemainder_jvm18.kt");
}
}
@TestMetadata("compiler/testData/codegen/bytecodeText/varargs")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -24288,6 +24288,26 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLiteralsWithSignedOverflow.kt");
}
@TestMetadata("unsignedLongDivide_jvm16.kt")
public void testUnsignedLongDivide_jvm16() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongDivide_jvm16.kt");
}
@TestMetadata("unsignedLongDivide_jvm18.kt")
public void testUnsignedLongDivide_jvm18() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongDivide_jvm18.kt");
}
@TestMetadata("unsignedLongRemainder_jvm16.kt")
public void testUnsignedLongRemainder_jvm16() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongRemainder_jvm16.kt");
}
@TestMetadata("unsignedLongRemainder_jvm18.kt")
public void testUnsignedLongRemainder_jvm18() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongRemainder_jvm18.kt");
}
@TestMetadata("unsignedTypePrefixIncrementDecrementBoxing.kt")
public void testUnsignedTypePrefixIncrementDecrementBoxing() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedTypePrefixIncrementDecrementBoxing.kt");
@@ -24293,6 +24293,26 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLiteralsWithSignedOverflow.kt");
}
@TestMetadata("unsignedLongDivide_jvm16.kt")
public void testUnsignedLongDivide_jvm16() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongDivide_jvm16.kt");
}
@TestMetadata("unsignedLongDivide_jvm18.kt")
public void testUnsignedLongDivide_jvm18() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongDivide_jvm18.kt");
}
@TestMetadata("unsignedLongRemainder_jvm16.kt")
public void testUnsignedLongRemainder_jvm16() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongRemainder_jvm16.kt");
}
@TestMetadata("unsignedLongRemainder_jvm18.kt")
public void testUnsignedLongRemainder_jvm18() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongRemainder_jvm18.kt");
}
@TestMetadata("unsignedTypePrefixIncrementDecrementBoxing.kt")
public void testUnsignedTypePrefixIncrementDecrementBoxing() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedTypePrefixIncrementDecrementBoxing.kt");
@@ -18738,6 +18738,26 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLiteralsWithSignedOverflow.kt");
}
@TestMetadata("unsignedLongDivide_jvm16.kt")
public void testUnsignedLongDivide_jvm16() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongDivide_jvm16.kt");
}
@TestMetadata("unsignedLongDivide_jvm18.kt")
public void testUnsignedLongDivide_jvm18() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongDivide_jvm18.kt");
}
@TestMetadata("unsignedLongRemainder_jvm16.kt")
public void testUnsignedLongRemainder_jvm16() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongRemainder_jvm16.kt");
}
@TestMetadata("unsignedLongRemainder_jvm18.kt")
public void testUnsignedLongRemainder_jvm18() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongRemainder_jvm18.kt");
}
@TestMetadata("unsignedTypePrefixIncrementDecrementBoxing.kt")
public void testUnsignedTypePrefixIncrementDecrementBoxing() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedTypePrefixIncrementDecrementBoxing.kt");
@@ -19788,6 +19788,26 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLiteralsWithSignedOverflow.kt");
}
@TestMetadata("unsignedLongDivide_jvm16.kt")
public void testUnsignedLongDivide_jvm16() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongDivide_jvm16.kt");
}
@TestMetadata("unsignedLongDivide_jvm18.kt")
public void testUnsignedLongDivide_jvm18() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongDivide_jvm18.kt");
}
@TestMetadata("unsignedLongRemainder_jvm16.kt")
public void testUnsignedLongRemainder_jvm16() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongRemainder_jvm16.kt");
}
@TestMetadata("unsignedLongRemainder_jvm18.kt")
public void testUnsignedLongRemainder_jvm18() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLongRemainder_jvm18.kt");
}
@TestMetadata("unsignedTypePrefixIncrementDecrementBoxing.kt")
public void testUnsignedTypePrefixIncrementDecrementBoxing() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedTypePrefixIncrementDecrementBoxing.kt");