this repo has no description
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