LCOV - code coverage report
Current view: top level - js/src/jit - ExecutableAllocator.h (source / functions) Hit Total Coverage
Test: output.info Lines: 8 29 27.6 %
Date: 2017-07-14 16:53:18 Functions: 3 10 30.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  *
       4             :  * Copyright (C) 2008 Apple Inc. All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  * 1. Redistributions of source code must retain the above copyright
      10             :  *    notice, this list of conditions and the following disclaimer.
      11             :  * 2. Redistributions in binary form must reproduce the above copyright
      12             :  *    notice, this list of conditions and the following disclaimer in the
      13             :  *    documentation and/or other materials provided with the distribution.
      14             :  *
      15             :  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
      16             :  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      17             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
      18             :  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
      19             :  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
      20             :  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      21             :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
      22             :  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
      23             :  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      24             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      25             :  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      26             :  */
      27             : 
      28             : #ifndef jit_ExecutableAllocator_h
      29             : #define jit_ExecutableAllocator_h
      30             : 
      31             : #include "mozilla/Maybe.h"
      32             : #include "mozilla/XorShift128PlusRNG.h"
      33             : 
      34             : #include <limits>
      35             : #include <stddef.h> // for ptrdiff_t
      36             : 
      37             : #include "jsalloc.h"
      38             : 
      39             : #ifdef JS_CODEGEN_ARM
      40             : #include "jit/arm/Architecture-arm.h"
      41             : #endif
      42             : #include "jit/arm/Simulator-arm.h"
      43             : #if defined(JS_CODEGEN_ARM64)
      44             : #include "jit/arm64/vixl/Cpu-vixl.h"
      45             : #endif
      46             : #include "jit/mips32/Simulator-mips32.h"
      47             : #include "jit/mips64/Simulator-mips64.h"
      48             : #include "jit/ProcessExecutableMemory.h"
      49             : #include "js/GCAPI.h"
      50             : #include "js/HashTable.h"
      51             : #include "js/Vector.h"
      52             : 
      53             : #if defined(__sparc__)
      54             : #ifdef __linux__  // bugzilla 502369
      55             : static void sync_instruction_memory(caddr_t v, u_int len)
      56             : {
      57             :     caddr_t end = v + len;
      58             :     caddr_t p = v;
      59             :     while (p < end) {
      60             :         asm("flush %0" : : "r" (p));
      61             :         p += 32;
      62             :     }
      63             : }
      64             : #else
      65             : extern  "C" void sync_instruction_memory(caddr_t v, u_int len);
      66             : #endif
      67             : #endif
      68             : 
      69             : #if defined(__linux__) &&                                             \
      70             :      (defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)) &&    \
      71             :      (!defined(JS_SIMULATOR_MIPS32) && !defined(JS_SIMULATOR_MIPS64))
      72             : #include <sys/cachectl.h>
      73             : #endif
      74             : 
      75             : #if defined(JS_CODEGEN_ARM) && defined(XP_IOS)
      76             : #include <libkern/OSCacheControl.h>
      77             : #endif
      78             : 
      79             : namespace JS {
      80             :     struct CodeSizes;
      81             : } // namespace JS
      82             : 
      83             : namespace js {
      84             : namespace jit {
      85             : 
      86             : enum CodeKind { ION_CODE = 0, BASELINE_CODE, REGEXP_CODE, OTHER_CODE };
      87             : 
      88             : class ExecutableAllocator;
      89             : class JitRuntime;
      90             : 
      91             : // These are reference-counted. A new one starts with a count of 1.
      92             : class ExecutablePool
      93             : {
      94             :     friend class ExecutableAllocator;
      95             : 
      96             :   private:
      97             :     struct Allocation {
      98             :         char* pages;
      99             :         size_t size;
     100             :     };
     101             : 
     102             :     ExecutableAllocator* m_allocator;
     103             :     char* m_freePtr;
     104             :     char* m_end;
     105             :     Allocation m_allocation;
     106             : 
     107             :     // Reference count for automatic reclamation.
     108             :     unsigned m_refCount:31;
     109             : 
     110             :     // Flag that can be used by algorithms operating on pools.
     111             :     bool m_mark:1;
     112             : 
     113             :     // Number of bytes currently used for Method and Regexp JIT code.
     114             :     size_t m_ionCodeBytes;
     115             :     size_t m_baselineCodeBytes;
     116             :     size_t m_regexpCodeBytes;
     117             :     size_t m_otherCodeBytes;
     118             : 
     119             :   public:
     120             :     void release(bool willDestroy = false);
     121             :     void release(size_t n, CodeKind kind);
     122             : 
     123             :     void addRef();
     124             : 
     125          81 :     ExecutablePool(ExecutableAllocator* allocator, Allocation a)
     126         243 :       : m_allocator(allocator), m_freePtr(a.pages), m_end(m_freePtr + a.size), m_allocation(a),
     127             :         m_refCount(1), m_mark(false), m_ionCodeBytes(0), m_baselineCodeBytes(0),
     128         243 :         m_regexpCodeBytes(0), m_otherCodeBytes(0)
     129          81 :     { }
     130             : 
     131             :     ~ExecutablePool();
     132             : 
     133           0 :     void mark() {
     134           0 :         MOZ_ASSERT(!m_mark);
     135           0 :         m_mark = true;
     136           0 :     }
     137           0 :     void unmark() {
     138           0 :         MOZ_ASSERT(m_mark);
     139           0 :         m_mark = false;
     140           0 :     }
     141           0 :     bool isMarked() const {
     142           0 :         return m_mark;
     143             :     }
     144             : 
     145             :   private:
     146             :     ExecutablePool(const ExecutablePool&) = delete;
     147             :     void operator=(const ExecutablePool&) = delete;
     148             : 
     149             :     void* alloc(size_t n, CodeKind kind);
     150             : 
     151             :     size_t available() const;
     152             : };
     153             : 
     154             : struct JitPoisonRange
     155             : {
     156             :     jit::ExecutablePool* pool;
     157             :     void* start;
     158             :     size_t size;
     159             : 
     160           0 :     JitPoisonRange(jit::ExecutablePool* pool, void* start, size_t size)
     161           0 :       : pool(pool), start(start), size(size)
     162           0 :     {}
     163             : };
     164             : 
     165             : typedef Vector<JitPoisonRange, 0, SystemAllocPolicy> JitPoisonRangeVector;
     166             : 
     167             : class ExecutableAllocator
     168             : {
     169             :     JSRuntime* rt_;
     170             : 
     171             :   public:
     172             :     explicit ExecutableAllocator(JSRuntime* rt);
     173             :     ~ExecutableAllocator();
     174             : 
     175             :     void purge();
     176             : 
     177             :     // alloc() returns a pointer to some memory, and also (by reference) a
     178             :     // pointer to reference-counted pool. The caller owns a reference to the
     179             :     // pool; i.e. alloc() increments the count before returning the object.
     180             :     void* alloc(JSContext* cx, size_t n, ExecutablePool** poolp, CodeKind type);
     181             : 
     182             :     void releasePoolPages(ExecutablePool* pool);
     183             : 
     184             :     void addSizeOfCode(JS::CodeSizes* sizes) const;
     185             : 
     186             :   private:
     187             :     static const size_t OVERSIZE_ALLOCATION = size_t(-1);
     188             : 
     189             :     static size_t roundUpAllocationSize(size_t request, size_t granularity);
     190             : 
     191             :     // On OOM, this will return an Allocation where pages is nullptr.
     192             :     ExecutablePool::Allocation systemAlloc(size_t n);
     193             :     static void systemRelease(const ExecutablePool::Allocation& alloc);
     194             : 
     195             :     ExecutablePool* createPool(size_t n);
     196             :     ExecutablePool* poolForSize(size_t n);
     197             : 
     198             :     static void reprotectPool(JSRuntime* rt, ExecutablePool* pool, ProtectionSetting protection);
     199             : 
     200             :   public:
     201             :     MOZ_MUST_USE
     202        4499 :     static bool makeWritable(void* start, size_t size)
     203             :     {
     204        4499 :         return ReprotectRegion(start, size, ProtectionSetting::Writable);
     205             :     }
     206             : 
     207             :     MOZ_MUST_USE
     208        4499 :     static bool makeExecutable(void* start, size_t size)
     209             :     {
     210        4499 :         return ReprotectRegion(start, size, ProtectionSetting::Executable);
     211             :     }
     212             : 
     213           0 :     void makeAllWritable() {
     214           0 :         reprotectAll(ProtectionSetting::Writable);
     215           0 :     }
     216           0 :     void makeAllExecutable() {
     217           0 :         reprotectAll(ProtectionSetting::Executable);
     218           0 :     }
     219             : 
     220             :     static void poisonCode(JSRuntime* rt, JitPoisonRangeVector& ranges);
     221             : 
     222             : #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) || defined(JS_SIMULATOR_ARM64) || defined(JS_CODEGEN_NONE)
     223           0 :     static void cacheFlush(void*, size_t)
     224             :     {
     225           0 :     }
     226             : #elif defined(JS_SIMULATOR_ARM) || defined(JS_SIMULATOR_MIPS32) || defined(JS_SIMULATOR_MIPS64)
     227             :     static void cacheFlush(void* code, size_t size)
     228             :     {
     229             :         js::jit::SimulatorProcess::FlushICache(code, size);
     230             :     }
     231             : #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     232             :     static void cacheFlush(void* code, size_t size)
     233             :     {
     234             : #if defined(_MIPS_ARCH_LOONGSON3A)
     235             :         // On Loongson3-CPUs, The cache flushed automatically
     236             :         // by hardware. Just need to execute an instruction hazard.
     237             :         uintptr_t tmp;
     238             :         asm volatile (
     239             :             ".set   push \n"
     240             :             ".set   noreorder \n"
     241             :             "move   %[tmp], $ra \n"
     242             :             "bal    1f \n"
     243             :             "daddiu $ra, 8 \n"
     244             :             "1: \n"
     245             :             "jr.hb  $ra \n"
     246             :             "move   $ra, %[tmp] \n"
     247             :             ".set   pop\n"
     248             :             :[tmp]"=&r"(tmp)
     249             :         );
     250             : #elif defined(__GNUC__)
     251             :         intptr_t end = reinterpret_cast<intptr_t>(code) + size;
     252             :         __builtin___clear_cache(reinterpret_cast<char*>(code), reinterpret_cast<char*>(end));
     253             : #else
     254             :         _flush_cache(reinterpret_cast<char*>(code), size, BCACHE);
     255             : #endif
     256             :     }
     257             : #elif defined(JS_CODEGEN_ARM) && (defined(__FreeBSD__) || defined(__NetBSD__))
     258             :     static void cacheFlush(void* code, size_t size)
     259             :     {
     260             :         __clear_cache(code, reinterpret_cast<char*>(code) + size);
     261             :     }
     262             : #elif (defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)) && defined(XP_IOS)
     263             :     static void cacheFlush(void* code, size_t size)
     264             :     {
     265             :         sys_icache_invalidate(code, size);
     266             :     }
     267             : #elif defined(JS_CODEGEN_ARM) && (defined(__linux__) || defined(ANDROID)) && defined(__GNUC__)
     268             :     static void cacheFlush(void* code, size_t size)
     269             :     {
     270             :         void* end = (void*)(reinterpret_cast<char*>(code) + size);
     271             :         asm volatile (
     272             :             "push    {r7}\n"
     273             :             "mov     r0, %0\n"
     274             :             "mov     r1, %1\n"
     275             :             "mov     r7, #0xf0000\n"
     276             :             "add     r7, r7, #0x2\n"
     277             :             "mov     r2, #0x0\n"
     278             :             "svc     0x0\n"
     279             :             "pop     {r7}\n"
     280             :             :
     281             :             : "r" (code), "r" (end)
     282             :             : "r0", "r1", "r2");
     283             : 
     284             :         if (ForceDoubleCacheFlush()) {
     285             :             void* start = (void*)((uintptr_t)code + 1);
     286             :             asm volatile (
     287             :                 "push    {r7}\n"
     288             :                 "mov     r0, %0\n"
     289             :                 "mov     r1, %1\n"
     290             :                 "mov     r7, #0xf0000\n"
     291             :                 "add     r7, r7, #0x2\n"
     292             :                 "mov     r2, #0x0\n"
     293             :                 "svc     0x0\n"
     294             :                 "pop     {r7}\n"
     295             :                 :
     296             :                 : "r" (start), "r" (end)
     297             :                 : "r0", "r1", "r2");
     298             :         }
     299             :     }
     300             : #elif defined(JS_CODEGEN_ARM64)
     301             :     static void cacheFlush(void* code, size_t size)
     302             :     {
     303             :         vixl::CPU::EnsureIAndDCacheCoherency(code, size);
     304             :     }
     305             : #elif defined(__sparc__)
     306             :     static void cacheFlush(void* code, size_t size)
     307             :     {
     308             :         sync_instruction_memory((caddr_t)code, size);
     309             :     }
     310             : #endif
     311             : 
     312             :   private:
     313             :     ExecutableAllocator(const ExecutableAllocator&) = delete;
     314             :     void operator=(const ExecutableAllocator&) = delete;
     315             : 
     316             :     void reprotectAll(ProtectionSetting);
     317             : 
     318             :     // These are strong references;  they keep pools alive.
     319             :     static const size_t maxSmallPools = 4;
     320             :     typedef js::Vector<ExecutablePool*, maxSmallPools, js::SystemAllocPolicy> SmallExecPoolVector;
     321             :     SmallExecPoolVector m_smallPools;
     322             : 
     323             :     // All live pools are recorded here, just for stats purposes.  These are
     324             :     // weak references;  they don't keep pools alive.  When a pool is destroyed
     325             :     // its reference is removed from m_pools.
     326             :     typedef js::HashSet<ExecutablePool*, js::DefaultHasher<ExecutablePool*>, js::SystemAllocPolicy>
     327             :             ExecPoolHashSet;
     328             :     ExecPoolHashSet m_pools;    // All pools, just for stats purposes.
     329             : };
     330             : 
     331             : } // namespace jit
     332             : } // namespace js
     333             : 
     334             : #endif /* jit_ExecutableAllocator_h */

Generated by: LCOV version 1.13