diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/CoreLibraryInvocationRewriter.java b/src/tools/android/java/com/google/devtools/build/android/desugar/CoreLibraryInvocationRewriter.java index 7a2e27d8bf8a13..944d37ed713f3f 100644 --- a/src/tools/android/java/com/google/devtools/build/android/desugar/CoreLibraryInvocationRewriter.java +++ b/src/tools/android/java/com/google/devtools/build/android/desugar/CoreLibraryInvocationRewriter.java @@ -20,6 +20,7 @@ import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; /** * Rewriter of default and static interface methods defined in some core libraries. @@ -32,6 +33,22 @@ public class CoreLibraryInvocationRewriter extends ClassVisitor { private final CoreLibrarySupport support; + @Override + public void visit( + int version, + int access, + String name, + String signature, + String superName, + String[] interfaces) { + super.visit(version, access, name, signature, superName, interfaces); + if (support.getMoveTarget(superName, "") != null) { + throw new UnsupportedOperationException( + String.format( + "Subclassing %s is unsupported: Contains a desugared factory method.", superName)); + } + } + public CoreLibraryInvocationRewriter(ClassVisitor cv, CoreLibrarySupport support) { super(Opcodes.ASM7, cv); this.support = support; @@ -45,6 +62,7 @@ public MethodVisitor visitMethod( } private class CoreLibraryMethodInvocationRewriter extends MethodVisitor { + public CoreLibraryMethodInvocationRewriter(MethodVisitor mv) { super(Opcodes.ASM7, mv); } @@ -53,7 +71,7 @@ public CoreLibraryMethodInvocationRewriter(MethodVisitor mv) { public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { Class coreInterface = support.getCoreInterfaceRewritingTarget(opcode, owner, name, desc, itf); - + boolean replaceConstructorUseWithFactoryMethod = false; if (coreInterface != null) { String coreInterfaceName = coreInterface.getName().replace('.', '/'); if (opcode == Opcodes.INVOKESTATIC) { @@ -63,8 +81,12 @@ public void visitMethodInsn(int opcode, String owner, String name, String desc, } if (opcode == Opcodes.INVOKESTATIC || opcode == Opcodes.INVOKESPECIAL) { - checkArgument(itf || opcode == Opcodes.INVOKESPECIAL, - "Expected interface to rewrite %s.%s : %s", owner, name, desc); + checkArgument( + itf || opcode == Opcodes.INVOKESPECIAL, + "Expected interface to rewrite %s.%s : %s", + owner, + name, + desc); if (coreInterface.isInterface()) { owner = InterfaceDesugaring.getCompanionClassName(coreInterfaceName); name = @@ -83,7 +105,17 @@ public void visitMethodInsn(int opcode, String owner, String name, String desc, } else { String newOwner = support.getMoveTarget(owner, name); if (newOwner != null) { - if (opcode != Opcodes.INVOKESTATIC) { + if ("".equals(name)) { + // Replace the invocation of a constructor with that of a static factory method. + replaceConstructorUseWithFactoryMethod = true; + opcode = Opcodes.INVOKESTATIC; + // Assumes the re-mapped factory method names are in the convention create$ + // defined in the desugar runtime library. + name = "create$" + owner.substring(owner.lastIndexOf('/') + 1); + desc = + Type.getMethodType(Type.getObjectType(owner), Type.getArgumentTypes(desc)) + .getDescriptor(); + } else if (opcode != Opcodes.INVOKESTATIC) { // assuming a static method desc = InterfaceDesugaring.companionDefaultMethodDescriptor(owner, desc); opcode = Opcodes.INVOKESTATIC; @@ -93,6 +125,19 @@ public void visitMethodInsn(int opcode, String owner, String name, String desc, } } super.visitMethodInsn(opcode, owner, name, desc, itf); + + // Compared with the constructor invocation, a factory method invocation pushes (areturn) the + // constructed object reference onto the operand stack of the invoker frame, leaving the + // operand stack in state {uninitialized 0, uninitialized 0, objectref}, the following + // instructions clears the extra values on the stack. + // + // TODO(b/144304047): Remove these extra byte code instructions once the preceding consecutive + // {new, dup} instructions are stripped out. + if (replaceConstructorUseWithFactoryMethod) { + super.visitInsn(Opcodes.DUP_X2); + super.visitInsn(Opcodes.POP); + super.visitInsn(Opcodes.POP2); + } } } } diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/runtime/TimeConversions.java b/src/tools/android/java/com/google/devtools/build/android/desugar/runtime/TimeConversions.java index ecd3075148fccf..3021c0dd9ca054 100644 --- a/src/tools/android/java/com/google/devtools/build/android/desugar/runtime/TimeConversions.java +++ b/src/tools/android/java/com/google/devtools/build/android/desugar/runtime/TimeConversions.java @@ -27,6 +27,15 @@ public static android.view.textclassifier.TextClassification.Request.Builder set return builder.setReferenceTime(toZonedDateTime(arg)); } + /** The factory method for the {@link android.app.admin.FreezePeriod}. */ + @SuppressWarnings("MethodName") // synthetic method. + public static android.app.admin.FreezePeriod create$FreezePeriod( + j$.time.MonthDay jStart, j$.time.MonthDay jEnd) { + java.time.MonthDay start = toMonthDay(jStart); + java.time.MonthDay end = toMonthDay(jEnd); + return new android.app.admin.FreezePeriod(start, end); + } + public static j$.time.MonthDay getStart(android.app.admin.FreezePeriod freezePeriod) { return fromMonthDay(freezePeriod.getStart()); } @@ -46,6 +55,12 @@ public static android.view.textclassifier.TextClassification.Request.Builder set : j$.time.MonthDay.of(monthDay.getMonthValue(), monthDay.getDayOfMonth()); } + private static java.time.MonthDay toMonthDay(j$.time.MonthDay monthDay) { + return monthDay == null + ? null + : java.time.MonthDay.of(monthDay.getMonthValue(), monthDay.getDayOfMonth()); + } + private static j$.time.ZonedDateTime fromZonedDateTime(java.time.ZonedDateTime dateTime) { if (dateTime == null) { return null;