Cast ByteBuffer to Buffer before calling position()

Change-Id: Id1405e5a3e8bb0dee201ba9a604c6af12a27cb14
diff --git a/src/main/java/com/android/tools/r8/code/InstructionFactory.java b/src/main/java/com/android/tools/r8/code/InstructionFactory.java
index 14d2f4b..83b0570 100644
--- a/src/main/java/com/android/tools/r8/code/InstructionFactory.java
+++ b/src/main/java/com/android/tools/r8/code/InstructionFactory.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.code;
 
 import com.android.tools.r8.graph.OffsetToObjectMapping;
-import java.nio.ByteBuffer;
 import java.nio.ShortBuffer;
 import java.util.ArrayList;
 import java.util.List;
@@ -18,11 +17,6 @@
     return create(high, opcode, stream, mapping);
   }
 
-  public Instruction[] readSequenceFrom(ByteBuffer buffer, int startIndex, int length,
-      OffsetToObjectMapping mapping) {
-    return readSequenceFrom(buffer.asShortBuffer(), startIndex, length, mapping);
-  }
-
   public Instruction[] readSequenceFrom(ShortBuffer buffer, int startIndex, int length,
       OffsetToObjectMapping mapping) {
     ShortBufferBytecodeStream range =
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index 825846e..26398d8 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -281,7 +281,7 @@
                     }
                     // Release use of the backing buffer now that accept has returned.
                     data.invalidate();
-                    byteBufferProvider.releaseByteBuffer(result.buffer);
+                    byteBufferProvider.releaseByteBuffer(result.buffer.asByteBuffer());
                     return true;
                   }));
         }
diff --git a/src/main/java/com/android/tools/r8/dex/BinaryReader.java b/src/main/java/com/android/tools/r8/dex/BinaryReader.java
index 5d51238..dd1cfee 100644
--- a/src/main/java/com/android/tools/r8/dex/BinaryReader.java
+++ b/src/main/java/com/android/tools/r8/dex/BinaryReader.java
@@ -10,14 +10,13 @@
 import com.android.tools.r8.utils.LebUtils;
 import com.android.tools.r8.utils.StreamUtils;
 import java.io.IOException;
-import java.nio.ByteBuffer;
 
 /**
  * Base class for reading binary content.
  */
 public abstract class BinaryReader {
   protected final Origin origin;
-  protected final ByteBuffer buffer;
+  protected final CompatByteBuffer buffer;
 
   protected BinaryReader(ProgramResource resource) throws ResourceException, IOException {
     this(resource.getOrigin(), StreamUtils.StreamToByteArrayClose(resource.getByteStream()));
@@ -26,7 +25,7 @@
   protected BinaryReader(Origin origin, byte[] bytes) {
     assert origin != null;
     this.origin = origin;
-    buffer = ByteBuffer.wrap(bytes);
+    buffer = CompatByteBuffer.wrap(bytes);
   }
 
   public Origin getOrigin() {
diff --git a/src/main/java/com/android/tools/r8/dex/CompatByteBuffer.java b/src/main/java/com/android/tools/r8/dex/CompatByteBuffer.java
new file mode 100644
index 0000000..6e32c6e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/dex/CompatByteBuffer.java
@@ -0,0 +1,135 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.dex;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.ShortBuffer;
+
+/**
+ * In JDK 9 ByteBuffer ByteBuffer.position(int) started overriding Buffer Buffer.position(int) along
+ * with various other methods defined on java.nio.Buffer. To avoid issues with running R8 on JDK 8
+ * we internally wrap any use of ByteBuffer and make sure access to the overridden methods happens
+ * only at the super type Buffer which is known to be in both JDKs.
+ */
+public class CompatByteBuffer {
+
+  private final ByteBuffer buffer;
+
+  public CompatByteBuffer(ByteBuffer buffer) {
+    this.buffer = buffer;
+  }
+
+  public static CompatByteBuffer wrap(byte[] bytes) {
+    return new CompatByteBuffer(ByteBuffer.wrap(bytes));
+  }
+
+  private Buffer asBuffer() {
+    return buffer;
+  }
+
+  public ByteBuffer asByteBuffer() {
+    return buffer;
+  }
+
+  // ----------------------------------------------------------------------------------------------
+  // 1.8 compatible calls to java.nio.Buffer methods.
+  // ----------------------------------------------------------------------------------------------
+
+  // The position(int) became overridden with a ByteBuffer return value.
+  public void position(int newPosition) {
+    asBuffer().position(newPosition);
+  }
+
+  // The rewind() became overridden with a ByteBuffer return value.
+  public void rewind() {
+    asBuffer().rewind();
+  }
+
+  // ----------------------------------------------------------------------------------------------
+  // Methods on java.nio.Buffer that are safely overridden or not non-overridden.
+  // ----------------------------------------------------------------------------------------------
+
+  // Note: array() overrides Buffer.array() in JDK 8 too, so that is safe for JDK 8 and 9.
+  public byte[] array() {
+    return asByteBuffer().array();
+  }
+
+  public int arrayOffset() {
+    return asByteBuffer().arrayOffset();
+  }
+
+  public int capacity() {
+    return asByteBuffer().capacity();
+  }
+
+  public boolean hasArray() {
+    return asByteBuffer().hasArray();
+  }
+
+  public boolean hasRemaining() {
+    return asByteBuffer().hasRemaining();
+  }
+
+  public int position() {
+    return asByteBuffer().position();
+  }
+
+  public int remaining() {
+    return asByteBuffer().remaining();
+  }
+
+  // ----------------------------------------------------------------------------------------------
+  // Methods on java.nio.ByteBuffer.
+  // ----------------------------------------------------------------------------------------------
+
+  public ShortBuffer asShortBuffer() {
+    return asByteBuffer().asShortBuffer();
+  }
+
+  public void order(ByteOrder bo) {
+    asByteBuffer().order(bo);
+  }
+
+  public byte get() {
+    return asByteBuffer().get();
+  }
+
+  public byte get(int index) {
+    return asByteBuffer().get(index);
+  }
+
+  public void get(byte[] dst) {
+    asByteBuffer().get(dst);
+  }
+
+  public int getInt() {
+    return asByteBuffer().getInt();
+  }
+
+  public int getInt(int offset) {
+    return asByteBuffer().getInt(offset);
+  }
+
+  public short getShort() {
+    return asByteBuffer().getShort();
+  }
+
+  public void put(byte aByte) {
+    asByteBuffer().put(aByte);
+  }
+
+  public void putShort(short aShort) {
+    asByteBuffer().putShort(aShort);
+  }
+
+  public void putInt(int anInteger) {
+    asByteBuffer().putInt(anInteger);
+  }
+
+  public void put(byte[] bytes) {
+    asByteBuffer().put(bytes);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java b/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java
index 000bc0e..2d1da51 100644
--- a/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java
+++ b/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java
@@ -22,7 +22,7 @@
   private static final int DEFAULT_BUFFER_SIZE = 256 * 1024;
 
   private final ByteBufferProvider byteBufferProvider;
-  private ByteBuffer byteBuffer;
+  private CompatByteBuffer byteBuffer;
 
   @VisibleForTesting
   DexOutputBuffer() {
@@ -37,16 +37,16 @@
   private void ensureSpaceFor(int bytes) {
     if (byteBuffer.remaining() < bytes) {
       int newSize = byteBuffer.capacity() + Math.max(byteBuffer.capacity(), bytes * 2);
-      ByteBuffer newBuffer = allocateByteBuffer(newSize);
-      System.arraycopy(byteBuffer.array(), 0, newBuffer.array(), 0, byteBuffer.position());
+      CompatByteBuffer newBuffer = allocateByteBuffer(newSize);
+      System.arraycopy(byteBuffer.array(), 0, newBuffer.array(), 0, position());
       newBuffer.position(byteBuffer.position());
       freeByteBuffer(byteBuffer);
       byteBuffer = newBuffer;
     }
   }
 
-  private ByteBuffer allocateByteBuffer(int size) {
-    ByteBuffer buffer = byteBufferProvider.acquireByteBuffer(size);
+  private CompatByteBuffer allocateByteBuffer(int size) {
+    CompatByteBuffer buffer = new CompatByteBuffer(byteBufferProvider.acquireByteBuffer(size));
     if (!buffer.hasArray()) {
       throw new CompilationError(
           "Provided byte-buffer is required to have an array backing, but does not.");
@@ -69,9 +69,9 @@
     return buffer;
   }
 
-  private void freeByteBuffer(ByteBuffer buffer) {
+  private void freeByteBuffer(CompatByteBuffer buffer) {
     assert buffer != null;
-    byteBufferProvider.releaseByteBuffer(buffer);
+    byteBufferProvider.releaseByteBuffer(buffer.asByteBuffer());
   }
 
   public void putUleb128(int value) {
@@ -133,7 +133,7 @@
   public int align(int bytes) {
     assert bytes > 0;
     int mask = bytes - 1;
-    int newPosition = (byteBuffer.position() + mask) & ~mask;
+    int newPosition = (position() + mask) & ~mask;
     ensureSpaceFor(newPosition - position());
     byteBuffer.position(newPosition);
     return newPosition;
@@ -165,8 +165,8 @@
     return byteBuffer.array();
   }
 
-  public ByteBuffer stealByteBuffer() {
-    ByteBuffer buffer = byteBuffer;
+  public CompatByteBuffer stealByteBuffer() {
+    CompatByteBuffer buffer = byteBuffer;
     byteBuffer = null;
     return buffer;
   }
diff --git a/src/main/java/com/android/tools/r8/dex/DexReader.java b/src/main/java/com/android/tools/r8/dex/DexReader.java
index d8997f7..45a0696 100644
--- a/src/main/java/com/android/tools/r8/dex/DexReader.java
+++ b/src/main/java/com/android/tools/r8/dex/DexReader.java
@@ -12,7 +12,6 @@
 import com.android.tools.r8.utils.DexVersion;
 import java.io.IOException;
 import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 
 /**
@@ -38,7 +37,7 @@
   }
 
   // Parse the magic header and determine the dex file version.
-  private int parseMagic(ByteBuffer buffer) {
+  private int parseMagic(CompatByteBuffer buffer) {
     try {
       buffer.get();
       buffer.rewind();
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index 1af80fa..4197da5 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -57,7 +57,6 @@
 import it.unimi.dsi.fastutil.objects.Object2IntMap;
 import it.unimi.dsi.fastutil.objects.Reference2IntLinkedOpenHashMap;
 import it.unimi.dsi.fastutil.objects.Reference2IntMap;
-import java.nio.ByteBuffer;
 import java.security.MessageDigest;
 import java.util.Arrays;
 import java.util.Collection;
@@ -77,10 +76,10 @@
   /** Simple pair of a byte buffer and its written length. */
   public static class ByteBufferResult {
     // Ownership of the buffer is transferred to the receiver of this result structure.
-    public final ByteBuffer buffer;
+    public final CompatByteBuffer buffer;
     public final int length;
 
-    private ByteBufferResult(ByteBuffer buffer, int length) {
+    private ByteBufferResult(CompatByteBuffer buffer, int length) {
       this.buffer = buffer;
       this.length = length;
     }
diff --git a/src/main/java/com/android/tools/r8/dex/VDexReader.java b/src/main/java/com/android/tools/r8/dex/VDexReader.java
index a3a5a2f..8d6f2d0 100644
--- a/src/main/java/com/android/tools/r8/dex/VDexReader.java
+++ b/src/main/java/com/android/tools/r8/dex/VDexReader.java
@@ -14,7 +14,6 @@
 import com.google.common.io.ByteStreams;
 import java.io.IOException;
 import java.io.InputStream;
-import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 
 /**
@@ -37,7 +36,7 @@
   }
 
   // Parse the magic header and determine the dex file version.
-  private int parseMagic(ByteBuffer buffer) {
+  private int parseMagic(CompatByteBuffer buffer) {
     int index = 0;
     for (byte prefixByte : VDEX_FILE_MAGIC_PREFIX) {
       if (buffer.get(index++) != prefixByte) {
diff --git a/src/test/java/com/android/tools/r8/code/InstructionFactoryTest.java b/src/test/java/com/android/tools/r8/code/InstructionFactoryTest.java
index ddd4f69..a1cfe7b 100644
--- a/src/test/java/com/android/tools/r8/code/InstructionFactoryTest.java
+++ b/src/test/java/com/android/tools/r8/code/InstructionFactoryTest.java
@@ -19,7 +19,7 @@
     ByteBuffer emptyBuffer = ByteBuffer.allocate(0);
     InstructionFactory factory = new InstructionFactory();
     Instruction[] instructions =
-        factory.readSequenceFrom(emptyBuffer, 0, 0, new OffsetToObjectMapping());
+        factory.readSequenceFrom(emptyBuffer.asShortBuffer(), 0, 0, new OffsetToObjectMapping());
     assertTrue(instructions.length == 0);
   }
 }