MIPS32r2: Fix Chromium runtime crash

Crash is caused by ldxc1 instruction, which traps when double values are
not aligned on 8-byte boundaries. Problem was tracked to SkChunkAlloc which
produces pointers aligned on 4-byte boundaries leading to misalignment.

This change makes sure that SkChunkAlloc will produce pointers that are
aligned to 8 bytes.

Appropriate tests are added to tests/MemsetTest.cpp

TEST=Build Chromium with Clang and run on MIPS32r2 platform
TEST=./out/Debug/dm --match Memset
BUG=130022
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1849183004

Review-Url: https://codereview.chromium.org/1849183004
diff --git a/gyp/common_conditions.gypi b/gyp/common_conditions.gypi
index 4f387e9..a9b0124 100644
--- a/gyp/common_conditions.gypi
+++ b/gyp/common_conditions.gypi
@@ -306,13 +306,17 @@
             ],
           }],
           [ '"mips" in skia_arch_type', {
-            'cflags': [ '-EL' ],
-            'conditions': [
-              [ 'mips_arch_variant == "mips32r2"', {
-                'cflags': [ '-march=mips32r2' ],
-                'conditions': [
-                  [ 'mips_dsp == 1', { 'cflags': [ '-mdsp'   ] }],
-                  [ 'mips_dsp == 2', { 'cflags': [ '-mdspr2' ] }],
+            'target_conditions': [
+              [ '_toolset == "target"', {
+                'cflags' : ['-EL'],
+                'conditions' : [
+                  [ 'mips_arch_variant == "mips32r2"', {
+                    'cflags': [ '-march=mips32r2' ],
+                    'conditions': [
+                      [ 'mips_dsp == 1', { 'cflags': [ '-mdsp'   ] }],
+                      [ 'mips_dsp == 2', { 'cflags': [ '-mdspr2' ] }],
+                    ],
+                  }],
                 ],
               }],
             ],
diff --git a/include/core/SkChunkAlloc.h b/include/core/SkChunkAlloc.h
index 9699842..bb4ec8f 100644
--- a/include/core/SkChunkAlloc.h
+++ b/include/core/SkChunkAlloc.h
@@ -33,7 +33,18 @@
         kThrow_AllocFailType
     };
 
+    /**
+     *  Allocates a memory block of size bytes.
+     *  On success: returns a pointer to beginning of memory block that is
+     *  8 byte aligned. The content of allocated block is not initialized.
+     *  On failure: calls abort() if called with kThrow_AllocFailType,
+     *  otherwise returns NULL pointer.
+     */
     void* alloc(size_t bytes, AllocFailType);
+
+    /**
+     *  Shortcut for calling alloc with kThrow_AllocFailType.
+     */
     void* allocThrow(size_t bytes) {
         return this->alloc(bytes, kThrow_AllocFailType);
     }
diff --git a/src/core/SkChunkAlloc.cpp b/src/core/SkChunkAlloc.cpp
index 8c5b8fb..bb52c46 100644
--- a/src/core/SkChunkAlloc.cpp
+++ b/src/core/SkChunkAlloc.cpp
@@ -23,7 +23,7 @@
     char*   fFreePtr;
     // data[] follows
 
-    size_t blockSize() {
+    size_t blockSize() const {
         char* start = this->startOfData();
         size_t bytes = fFreePtr - start;
         return fFreeSize + bytes;
@@ -35,8 +35,8 @@
         fFreePtr = this->startOfData();
     }
 
-    char* startOfData() {
-        return reinterpret_cast<char*>(this + 1);
+    char* startOfData() const {
+        return reinterpret_cast<char*>(SkAlign8(reinterpret_cast<size_t>(this + 1)));
     }
 
     static void FreeChain(Block* block) {
@@ -49,7 +49,7 @@
 
     bool contains(const void* addr) const {
         const char* ptr = reinterpret_cast<const char*>(addr);
-        return ptr >= (const char*)(this + 1) && ptr < fFreePtr;
+        return ptr >= this->startOfData() && ptr < fFreePtr;
     }
 };
 
@@ -121,7 +121,7 @@
         size = fChunkSize;
     }
 
-    Block* block = (Block*)sk_malloc_flags(sizeof(Block) + size,
+    Block* block = (Block*)sk_malloc_flags(SkAlign8(sizeof(Block)) + size,
                         ftype == kThrow_AllocFailType ? SK_MALLOC_THROW : 0);
 
     if (block) {
@@ -137,7 +137,7 @@
 }
 
 SkChunkAlloc::Block* SkChunkAlloc::addBlockIfNecessary(size_t bytes, AllocFailType ftype) {
-    SkASSERT(SkIsAlign4(bytes));
+    SkASSERT(SkIsAlign8(bytes));
 
     if (!fBlock || bytes > fBlock->fFreeSize) {
         Block* block = this->newBlock(bytes, ftype);
@@ -160,7 +160,7 @@
 void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) {
     SkDEBUGCODE(this->validate();)
 
-    bytes = SkAlign4(bytes);
+    bytes = SkAlign8(bytes);
 
     Block* block = this->addBlockIfNecessary(bytes, ftype);
     if (!block) {
@@ -173,6 +173,7 @@
     block->fFreeSize -= bytes;
     block->fFreePtr = ptr + bytes;
     SkDEBUGCODE(this->validate();)
+    SkASSERT(SkIsAlign8((size_t)ptr));
     return ptr;
 }
 
diff --git a/tests/MemsetTest.cpp b/tests/MemsetTest.cpp
index e1f844e..fb5a337 100644
--- a/tests/MemsetTest.cpp
+++ b/tests/MemsetTest.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "SkChunkAlloc.h"
+#include "SkRandom.h"
 #include "SkUtils.h"
 #include "Test.h"
 
@@ -23,6 +24,14 @@
     return ptr;
 }
 
+static void check_alloc_alignment(skiatest::Reporter* reporter,
+                                  SkChunkAlloc* alloc, size_t size) {
+    const size_t kAlignment = 8;
+    void* ptr = alloc->allocThrow(size);
+    REPORTER_ASSERT(reporter, ptr != nullptr);
+    REPORTER_ASSERT(reporter, (size_t)ptr % kAlignment == 0);
+}
+
 static void test_chunkalloc(skiatest::Reporter* reporter) {
     static const size_t kMin = 1024;
     SkChunkAlloc alloc(kMin);
@@ -76,6 +85,14 @@
     REPORTER_ASSERT(reporter, freed == kMin);
     check_alloc(reporter, alloc, 2*kMin, size, 2);
     REPORTER_ASSERT(reporter, !alloc.contains(ptr));
+
+    //------------------------------------------------------------------------
+    // test the alignment
+    alloc.reset();
+    SkRandom rand;
+    for (int i = 0; i < 1000; i++) {
+        check_alloc_alignment(reporter, &alloc, rand.nextU16());
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////