Merge "Fix DirectByteBufferAlignment"
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/SliceDirectByteBufferTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/SliceDirectByteBufferTest.java
index c00694a..967af33 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/SliceDirectByteBufferTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/SliceDirectByteBufferTest.java
@@ -4,9 +4,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *     http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,7 +21,7 @@
 
     protected void setUp() throws Exception {
         super.setUp();
-        buf.position(1).limit(BUFFER_LENGTH-1);
+        buf.position(1);
         buf = buf.slice();
         baseBuf = buf;
     }
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/SliceSliceDirectByteBufferTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/SliceSliceDirectByteBufferTest.java
new file mode 100644
index 0000000..b5e5b11
--- /dev/null
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/SliceSliceDirectByteBufferTest.java
@@ -0,0 +1,34 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.tests.java.nio;
+
+
+public class SliceSliceDirectByteBufferTest extends DirectByteBufferTest {
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        buf.position(1);
+        buf = buf.slice();
+        buf.position(1);
+        buf = buf.slice();
+        baseBuf = buf;
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+}
diff --git a/ojluni/src/main/java/java/nio/ByteBuffer.java b/ojluni/src/main/java/java/nio/ByteBuffer.java
index 0434994..b8f2aa0 100644
--- a/ojluni/src/main/java/java/nio/ByteBuffer.java
+++ b/ojluni/src/main/java/java/nio/ByteBuffer.java
@@ -27,7 +27,7 @@
 
 package java.nio;
 
-
+import dalvik.system.VMRuntime;
 
 
 /**
@@ -304,7 +304,14 @@
         if (capacity < 0) {
             throw new IllegalArgumentException("capacity < 0: " + capacity);
         }
-        return new DirectByteBuffer(capacity);
+
+        VMRuntime runtime = VMRuntime.getRuntime();
+        byte[] hb = (byte[])runtime.newNonMovableArray(byte.class, capacity + 7);
+        long address = runtime.addressOf(hb);
+        // Offset is set to handle the alignment
+        // http://b/16449607
+        int offset = (int)(((address + 7) & ~(long)7) - address);
+        return new DirectByteBuffer(capacity, address, hb, offset);
     }
 
 
diff --git a/ojluni/src/main/java/java/nio/DirectByteBuffer.java b/ojluni/src/main/java/java/nio/DirectByteBuffer.java
index 51f63c6..a5b9e0c 100644
--- a/ojluni/src/main/java/java/nio/DirectByteBuffer.java
+++ b/ojluni/src/main/java/java/nio/DirectByteBuffer.java
@@ -31,7 +31,6 @@
 import sun.nio.ch.DirectBuffer;
 import libcore.io.SizeOf;
 import libcore.io.Memory;
-import dalvik.system.VMRuntime;
 
 class DirectByteBuffer extends MappedByteBuffer
     implements DirectBuffer {
@@ -53,15 +52,16 @@
 
     private Cleaner cleaner;
 
+    private long actualAddress;
+
     public Cleaner cleaner() { return cleaner; }
 
-    DirectByteBuffer(int capacity) {
-        super(-1, 0, capacity, capacity, (byte[]) VMRuntime.getRuntime()
-              .newNonMovableArray(byte.class, capacity), 0);
-        VMRuntime runtime = VMRuntime.getRuntime();
-        address = runtime.addressOf(hb);
+    DirectByteBuffer(int capacity, long address, byte[] hb, int offset) {
+        super(-1, 0, capacity, capacity, hb, offset);
         // Only have references to java objects, no need for a cleaner since the GC will do all
         // the work.
+        this.address = address + offset;
+        this.actualAddress = address;
         cleaner = null;
         this.isReadOnly = false;
         att = null;
@@ -70,6 +70,7 @@
     DirectByteBuffer(long addr, int cap, Object ob) {
         super(-1, 0, cap, cap);
         address = addr;
+        actualAddress = addr;
         cleaner = null;
         att = ob;
     }
@@ -79,6 +80,7 @@
     private DirectByteBuffer(long addr, int cap) {
         super(-1, 0, cap, cap);
         address = addr;
+        actualAddress = addr;
         cleaner = null;
         att = null;
     }
@@ -98,6 +100,7 @@
         super(-1, 0, cap, cap, fd);
         this.isReadOnly = isReadOnly;
         address = addr;
+        actualAddress = addr;
         cleaner = Cleaner.create(this, unmapper);
         att = null;
     }
@@ -115,7 +118,8 @@
                      int off, boolean isReadOnly) {
         super(mark, pos, lim, cap, db.hb, off);
         this.isReadOnly = isReadOnly;
-        address = db.address() + off;
+        address = db.address;
+        actualAddress = db.actualAddress;
         cleaner = null;
         att = db;
     }
@@ -124,11 +128,11 @@
         if (!isAccessible) {
             throw new IllegalStateException("buffer is inaccessible");
         }
-        int pos = this.position();
-        int lim = this.limit();
+        int pos = position();
+        int lim = limit();
         assert (pos <= lim);
         int rem = (pos <= lim ? lim - pos : 0);
-        int off = (pos << 0);
+        int off = (pos << 0) + offset;
         assert (off >= 0);
         return new DirectByteBuffer(this, -1, 0, rem, rem, off, isReadOnly);
     }
@@ -142,7 +146,7 @@
                                     this.position(),
                                     this.limit(),
                                     this.capacity(),
-                                    0,
+                                    offset,
                                     isReadOnly);
     }
 
@@ -155,7 +159,7 @@
                                     this.position(),
                                     this.limit(),
                                     this.capacity(),
-                                    0,
+                                    offset,
                                     true);
     }
 
@@ -164,10 +168,10 @@
     }
 
     private long ix(int i) {
-        return address + (i << 0);
+        return actualAddress + offset + (i << 0);
     }
 
-    public byte get(long a) {
+    private byte get(long a) {
         return Memory.peekByte(a);
     }
 
@@ -175,14 +179,14 @@
         if (!isAccessible) {
             throw new IllegalStateException("buffer is inaccessible");
         }
-        return get(address + nextGetIndex());
+        return get(ix(nextGetIndex()));
     }
 
     public byte get(int i) {
         if (!isAccessible) {
             throw new IllegalStateException("buffer is inaccessible");
         }
-        return get(address + checkIndex(i));
+        return get(ix(checkIndex(i)));
     }
 
     public ByteBuffer get(byte[] dst, int dstOffset, int length) {
@@ -196,7 +200,7 @@
         int rem = (pos <= lim ? lim - pos : 0);
         if (length > rem)
             throw new BufferUnderflowException();
-        Memory.peekByteArray(address + pos,
+        Memory.peekByteArray(ix(pos),
                              dst, dstOffset, length);
         position = pos + length;
         return this;
@@ -265,7 +269,7 @@
         int rem = (pos <= lim ? lim - pos : 0);
         if (length > rem)
             throw new BufferOverflowException();
-        Memory.pokeByteArray(address + pos,
+        Memory.pokeByteArray(ix(pos),
                              src, srcOffset, length);
         position = pos + length;
         return this;
@@ -282,7 +286,7 @@
         int lim = limit();
         assert (pos <= lim);
         int rem = (pos <= lim ? lim - pos : 0);
-        Memory.memmove(this, 0, this, position, remaining());
+        System.arraycopy(hb, position + offset, hb, offset, remaining());
         position(rem);
         limit(capacity());
         discardMark();
@@ -320,7 +324,7 @@
         if (newPosition > limit()) {
             throw new BufferUnderflowException();
         }
-        char x = (char) Memory.peekShort(address + position, !nativeByteOrder);
+        char x = (char) Memory.peekShort(ix(position), !nativeByteOrder);
         position = newPosition;
         return x;
     }
@@ -330,7 +334,7 @@
             throw new IllegalStateException("buffer is inaccessible");
         }
         checkIndex(i, SizeOf.CHAR);
-        char x = (char)Memory.peekShort(address + i, !nativeByteOrder);
+        char x = (char)Memory.peekShort(ix(i), !nativeByteOrder);
         return x;
     }