1// Copyright 2017, VIXL authors 2// All rights reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions are met: 6// 7// * Redistributions of source code must retain the above copyright notice, 8// this list of conditions and the following disclaimer. 9// * Redistributions in binary form must reproduce the above copyright notice, 10// this list of conditions and the following disclaimer in the documentation 11// and/or other materials provided with the distribution. 12// * Neither the name of ARM Limited nor the names of its contributors may be 13// used to endorse or promote products derived from this software without 14// specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24// OR TORT (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#include "code-buffer-vixl.h" 28#include "utils-vixl.h" 29 30namespace vixl { 31 32CodeBuffer::CodeBuffer(size_t capacity) 33 : buffer_(NULL), 34 managed_(true), 35 cursor_(NULL), 36 dirty_(false), 37 capacity_(capacity) { 38 if (capacity_ == 0) { 39 return; 40 } 41#ifdef VIXL_CODE_BUFFER_MALLOC 42 buffer_ = reinterpret_cast<byte*>(malloc(capacity_)); 43#elif defined(VIXL_CODE_BUFFER_MMAP) 44 buffer_ = reinterpret_cast<byte*>(mmap(NULL, 45 capacity, 46 PROT_READ | PROT_WRITE, 47 MAP_PRIVATE | MAP_ANONYMOUS, 48 -1, 49 0)); 50#else 51#error Unknown code buffer allocator. 52#endif 53 VIXL_CHECK(buffer_ != NULL); 54 // Aarch64 instructions must be word aligned, we assert the default allocator 55 // always returns word align memory. 56 if (buffer_ != MAP_FAILED) { 57 VIXL_ASSERT(IsWordAligned(buffer_)); 58 cursor_ = buffer_; 59 } 60} 61 62 63CodeBuffer::CodeBuffer(byte* buffer, size_t capacity) 64 : buffer_(reinterpret_cast<byte*>(buffer)), 65 managed_(false), 66 cursor_(reinterpret_cast<byte*>(buffer)), 67 dirty_(false), 68 capacity_(capacity) { 69 VIXL_ASSERT(buffer_ != NULL); 70} 71 72 73CodeBuffer::~CodeBuffer() VIXL_NEGATIVE_TESTING_ALLOW_EXCEPTION { 74 // VIXL_ASSERT(!IsDirty()); // Use own allocator - not applied 75 if (managed_) { 76#ifdef VIXL_CODE_BUFFER_MALLOC 77 free(buffer_); 78#elif defined(VIXL_CODE_BUFFER_MMAP) 79 if (buffer_ != MAP_FAILED) { 80 [[maybe_unused]] int res = munmap(buffer_, capacity_); 81 // Success unmap position 82 VIXL_ASSERT(res == 0); 83 if ((mmap_max_ != 0) && (capacity_ > mmap_max_)) { 84 // Force crash - allocated too much 85 printf(" Allocated too much memory.\n"); 86 VIXL_UNREACHABLE(); 87 } 88 } 89#else 90#error Unknown code buffer allocator. 91#endif 92 } 93} 94 95 96void CodeBuffer::SetExecutable() { 97#ifdef VIXL_CODE_BUFFER_MMAP 98 int ret = mprotect(buffer_, capacity_, PROT_READ | PROT_EXEC); 99 VIXL_CHECK(ret == 0); 100#else 101 // This requires page-aligned memory blocks, which we can only guarantee with 102 // mmap. 103 VIXL_UNIMPLEMENTED(); 104#endif 105} 106 107 108void CodeBuffer::SetWritable() { 109#ifdef VIXL_CODE_BUFFER_MMAP 110 int ret = mprotect(buffer_, capacity_, PROT_READ | PROT_WRITE); 111 VIXL_CHECK(ret == 0); 112#else 113 // This requires page-aligned memory blocks, which we can only guarantee with 114 // mmap. 115 VIXL_UNIMPLEMENTED(); 116#endif 117} 118 119// For some reason OHOS toolchain doesn't have this function 120#ifdef PANDA_TARGET_MOBILE 121char* stpcpy (char *dst, const char *src) { 122 const size_t len = strlen (src); 123 return (char *) memcpy (dst, src, len + 1) + len; 124} 125#endif 126 127void CodeBuffer::EmitString(const char* string) { 128 const auto len = strlen(string) + 1; 129 VIXL_ASSERT(HasSpaceFor(len)); 130 char* dst = reinterpret_cast<char*>(cursor_); 131 dirty_ = true; 132 memcpy(dst, string, len); 133 cursor_ = reinterpret_cast<byte*>(dst + len); 134} 135 136 137void CodeBuffer::EmitData(const void* data, size_t size) { 138 VIXL_ASSERT(HasSpaceFor(size)); 139 dirty_ = true; 140 memcpy(cursor_, data, size); 141 cursor_ = cursor_ + size; 142} 143 144 145void CodeBuffer::UpdateData(size_t offset, const void* data, size_t size) { 146 dirty_ = true; 147 byte* dst = buffer_ + offset; 148 VIXL_ASSERT(dst + size <= cursor_); 149 memcpy(dst, data, size); 150} 151 152 153void CodeBuffer::Align() { 154 byte* end = AlignUp(cursor_, 4); 155 const size_t padding_size = end - cursor_; 156 VIXL_ASSERT(padding_size <= 4); 157 EmitZeroedBytes(static_cast<int>(padding_size)); 158} 159 160void CodeBuffer::EmitZeroedBytes(int n) { 161 EnsureSpaceFor(n); 162 dirty_ = true; 163 memset(cursor_, 0, n); 164 cursor_ += n; 165} 166 167void CodeBuffer::Reset() { 168#ifdef VIXL_DEBUG 169 if (managed_) { 170 // Fill with zeros (there is no useful value common to A32 and T32). 171 memset(buffer_, 0, capacity_); 172 } 173#endif 174 cursor_ = buffer_; 175 SetClean(); 176} 177 178 179void CodeBuffer::Grow(size_t new_capacity) { 180 VIXL_ASSERT(managed_); 181 VIXL_ASSERT(new_capacity > capacity_); 182 ptrdiff_t cursor_offset = GetCursorOffset(); 183 VIXL_ASSERT(false); 184 // Do not support grow with our allocators 185#ifdef VIXL_CODE_BUFFER_MALLOC 186 buffer_ = static_cast<byte*>(realloc(buffer_, new_capacity)); 187 VIXL_CHECK(buffer_ != NULL); 188#elif defined(VIXL_CODE_BUFFER_MMAP) 189 buffer_ = static_cast<byte*>( 190 mremap(buffer_, capacity_, new_capacity, MREMAP_MAYMOVE)); 191 VIXL_CHECK(buffer_ != MAP_FAILED); 192 if ((mmap_max_ != 0) && (new_capacity > mmap_max_)) { 193 // Force crash - allocated too much 194 printf(" Allocated too much memory.\n"); 195 VIXL_UNREACHABLE(); 196 } 197#else 198#error Unknown code buffer allocator. 199#endif 200 cursor_ = buffer_ + cursor_offset; 201 capacity_ = new_capacity; 202} 203 204 205} // namespace vixl 206