this repo has no description
at trunk 111 lines 3.7 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2// Copyright (c) 2013, the Dart project authors and Facebook, Inc. and its 3// affiliates. Please see the AUTHORS-Dart file for details. All rights 4// reserved. Use of this source code is governed by a BSD-style license that 5// can be found in the LICENSE-Dart file. 6 7#include "assembler-utils.h" 8 9#include <cstdlib> 10 11#include "assembler-x64.h" 12#include "memory-region.h" 13#include "utils.h" 14 15namespace py { 16 17#ifndef NDEBUG 18AssemblerBuffer::EnsureCapacity::EnsureCapacity(AssemblerBuffer* buffer) { 19 if (buffer->cursor() >= buffer->limit()) buffer->extendCapacity(); 20 // In debug mode, we save the assembler buffer along with the gap 21 // size before we start emitting to the buffer. This allows us to 22 // check that any single generated instruction doesn't overflow the 23 // limit implied by the minimum gap size. 24 buffer_ = buffer; 25 gap_ = computeGap(); 26 // Make sure that extending the capacity leaves a big enough gap 27 // for any kind of instruction. 28 DCHECK(gap_ >= kMinimumGap, "assert()"); 29 // Mark the buffer as having ensured the capacity. 30 DCHECK(!buffer->hasEnsuredCapacity(), "assert()"); // Cannot nest. 31 buffer->has_ensured_capacity_ = true; 32} 33 34AssemblerBuffer::EnsureCapacity::~EnsureCapacity() { 35 // Unmark the buffer, so we cannot emit after this. 36 buffer_->has_ensured_capacity_ = false; 37 // Make sure the generated instruction doesn't take up more 38 // space than the minimum gap. 39 word delta = gap_ - computeGap(); 40 DCHECK(delta <= kMinimumGap, "assert()"); 41} 42#endif 43 44AssemblerBuffer::AssemblerBuffer() { 45 static const word initial_buffer_capacity = 4 * kKiB; 46 contents_ = reinterpret_cast<uword>(std::malloc(initial_buffer_capacity)); 47 cursor_ = contents_; 48 limit_ = computeLimit(contents_, initial_buffer_capacity); 49 fixup_ = nullptr; 50#ifndef NDEBUG 51 has_ensured_capacity_ = false; 52 fixups_processed_ = false; 53#endif 54 55 // Verify internal state. 56 DCHECK(capacity() == initial_buffer_capacity, "assert()"); 57 DCHECK(size() == 0, "assert()"); 58} 59 60AssemblerBuffer::~AssemblerBuffer() { 61 std::free(reinterpret_cast<void*>(contents_)); 62 cursor_ = 0; 63} 64 65void AssemblerBuffer::processFixups(MemoryRegion region) { 66 AssemblerFixup* fixup = fixup_; 67 while (fixup != nullptr) { 68 fixup->process(region, fixup->position()); 69 fixup = fixup->previous(); 70 } 71} 72 73void AssemblerBuffer::finalizeInstructions(MemoryRegion instructions) { 74 // Copy the instructions from the buffer. 75 MemoryRegion from(reinterpret_cast<void*>(contents()), size()); 76 instructions.copyFrom(0, from); 77 // Process fixups in the instructions. 78 processFixups(instructions); 79#ifndef NDEBUG 80 fixups_processed_ = true; 81#endif 82} 83 84void AssemblerBuffer::extendCapacity() { 85 word old_size = size(); 86 word old_capacity = capacity(); 87 word new_capacity = Utils::minimum(old_capacity * 2, old_capacity + 1 * kMiB); 88 if (new_capacity < old_capacity) { 89 UNREACHABLE("Unexpected overflow in AssemblerBuffer::ExtendCapacity"); 90 } 91 92 // Allocate the new data area and copy contents of the old one to it. 93 uword new_contents = reinterpret_cast<uword>(std::malloc(new_capacity)); 94 memmove(reinterpret_cast<void*>(new_contents), 95 reinterpret_cast<void*>(contents_), old_size); 96 97 // Compute the relocation delta and switch to the new contents area. 98 word delta = new_contents - contents_; 99 std::free(reinterpret_cast<void*>(contents_)); 100 contents_ = new_contents; 101 102 // Update the cursor and recompute the limit. 103 cursor_ += delta; 104 limit_ = computeLimit(new_contents, new_capacity); 105 106 // Verify internal state. 107 DCHECK(capacity() == new_capacity, "assert()"); 108 DCHECK(size() == old_size, "assert()"); 109} 110 111} // namespace py