From d517e18b78152c808c5e73f86bb42b14a60320fd Mon Sep 17 00:00:00 2001
From: Michael Kamprath <michael@claireware.com>
Date: Sun, 25 Dec 2016 13:54:26 -0800
Subject: [PATCH] [SPARK-18819] Double alignment on ARM

On ARM 32 bit platforms, such as ARM71, double access needs to be
aligned to 8-byte coundaries. These changes ensure that happens.
This is intended to be a patch commit that can be used to create
custom builds of Spark for the ARM 32-bit platforms.
---
 .../org/apache/spark/util/sketch/Platform.java     |  6 +++--
 .../java/org/apache/spark/unsafe/Platform.java     |  9 +++++--
 .../org/apache/spark/unsafe/PlatformUtilSuite.java | 29 +++++++++++++++++++---
 3 files changed, 37 insertions(+), 7 deletions(-)

diff --git a/common/sketch/src/main/java/org/apache/spark/util/sketch/Platform.java b/common/sketch/src/main/java/org/apache/spark/util/sketch/Platform.java
index 75d6a6b..27690bd 100644
--- a/common/sketch/src/main/java/org/apache/spark/util/sketch/Platform.java
+++ b/common/sketch/src/main/java/org/apache/spark/util/sketch/Platform.java
@@ -84,11 +84,13 @@ final class Platform {
   }
 
   public static double getDouble(Object object, long offset) {
-    return _UNSAFE.getDouble(object, offset);
+    // Using Long buffer for platforms requiring double byte alignment
+    return Double.longBitsToDouble(_UNSAFE.getLong(object, offset));
   }
 
   public static void putDouble(Object object, long offset, double value) {
-    _UNSAFE.putDouble(object, offset, value);
+    // Using Long buffer for platforms requiring double byte alignment
+    _UNSAFE.putLong(object, offset, Double.doubleToRawLongBits(value));
   }
 
   public static Object getObjectVolatile(Object object, long offset) {
diff --git a/common/unsafe/src/main/java/org/apache/spark/unsafe/Platform.java b/common/unsafe/src/main/java/org/apache/spark/unsafe/Platform.java
index 671b8c7..443283e 100644
--- a/common/unsafe/src/main/java/org/apache/spark/unsafe/Platform.java
+++ b/common/unsafe/src/main/java/org/apache/spark/unsafe/Platform.java
@@ -22,10 +22,14 @@ import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.nio.ByteBuffer;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import sun.misc.Cleaner;
 import sun.misc.Unsafe;
 
 public final class Platform {
+  private static final Logger logger = LoggerFactory.getLogger(Platform.class);
 
   private static final Unsafe _UNSAFE;
 
@@ -44,6 +48,7 @@ public final class Platform {
   public static final int DOUBLE_ARRAY_OFFSET;
 
   private static final boolean unaligned;
+
   static {
     boolean _unaligned;
     // use reflection to access unaligned field
@@ -119,11 +124,11 @@ public final class Platform {
   }
 
   public static double getDouble(Object object, long offset) {
-    return _UNSAFE.getDouble(object, offset);
+    return Double.longBitsToDouble(_UNSAFE.getLong(object, offset));
   }
 
   public static void putDouble(Object object, long offset, double value) {
-    _UNSAFE.putDouble(object, offset, value);
+    _UNSAFE.putLong(object, offset, Double.doubleToRawLongBits(value));
   }
 
   public static Object getObjectVolatile(Object object, long offset) {
diff --git a/common/unsafe/src/test/java/org/apache/spark/unsafe/PlatformUtilSuite.java b/common/unsafe/src/test/java/org/apache/spark/unsafe/PlatformUtilSuite.java
index a77ba826..a28a7d4 100644
--- a/common/unsafe/src/test/java/org/apache/spark/unsafe/PlatformUtilSuite.java
+++ b/common/unsafe/src/test/java/org/apache/spark/unsafe/PlatformUtilSuite.java
@@ -17,12 +17,12 @@
 
 package org.apache.spark.unsafe;
 
-import org.apache.spark.unsafe.memory.MemoryAllocator;
-import org.apache.spark.unsafe.memory.MemoryBlock;
-
 import org.junit.Assert;
 import org.junit.Test;
 
+import org.apache.spark.unsafe.memory.MemoryBlock;
+import org.apache.spark.unsafe.memory.MemoryAllocator;
+
 public class PlatformUtilSuite {
 
   @Test
@@ -74,4 +74,27 @@ public class PlatformUtilSuite {
       Platform.getByte(offheap.getBaseObject(), offheap.getBaseOffset()),
       MemoryAllocator.MEMORY_DEBUG_FILL_CLEAN_VALUE);
   }
+
+  /**
+   * This test ensures that double access is handled correctly for the host platform.
+   * On platforms that require double access to be aligned to 8-byte boundaries, this
+   * test should pass and not cause the JVM to segfault.
+   */
+  @Test
+  public void unalignedDoublePutAndGet() {
+    MemoryBlock testBuffer = MemoryBlock.fromLongArray(new long[20]);
+
+    // write a double to an unaligned location
+    long unalignedOffset = testBuffer.getBaseOffset() + 3;
+    // double check unalignment just to be sure:
+    if (unalignedOffset % 8 == 0) {
+      unalignedOffset++;
+    }
+
+    Platform.putDouble(testBuffer.getBaseObject(), unalignedOffset, 3.14159);
+
+    double foundDouble = Platform.getDouble(testBuffer.getBaseObject(), unalignedOffset);
+
+    Assert.assertEquals(3.14159, foundDouble, 0.000001);
+  }
 }
-- 
2.10.1 (Apple Git-78)

