blob: f6ca6908861c3f430b21c173aa0957c88d0100cd [file] [log] [blame]
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -07001// Copyright 2011 Google Inc. All Rights Reserved.
2
3#include <algorithm>
4#include <vector>
5#include "src/assembler.h"
6#include "src/globals.h"
7#include "src/memory_region.h"
8
9namespace android {
10namespace runtime {
11
12static byte* NewContents(size_t capacity) {
13 byte* result = new byte[capacity];
14#if defined(DEBUG)
15 // Initialize the buffer with kBreakPointInstruction to force a break
16 // point if we ever execute an uninitialized part of the code buffer.
17 Assembler::InitializeMemoryWithBreakpoints(result, capacity);
18#endif
19 return result;
20}
21
22
23#if defined(DEBUG)
24AssemblerBuffer::EnsureCapacity::EnsureCapacity(AssemblerBuffer* buffer) {
25 if (buffer->cursor() >= buffer->limit()) buffer->ExtendCapacity();
26 // In debug mode, we save the assembler buffer along with the gap
27 // size before we start emitting to the buffer. This allows us to
28 // check that any single generated instruction doesn't overflow the
29 // limit implied by the minimum gap size.
30 buffer_ = buffer;
31 gap_ = ComputeGap();
32 // Make sure that extending the capacity leaves a big enough gap
33 // for any kind of instruction.
34 CHECK(gap_ >= kMinimumGap);
35 // Mark the buffer as having ensured the capacity.
36 CHECK(!buffer->HasEnsuredCapacity()); // Cannot nest.
37 buffer->has_ensured_capacity_ = true;
38}
39
40
41AssemblerBuffer::EnsureCapacity::~EnsureCapacity() {
42 // Unmark the buffer, so we cannot emit after this.
43 buffer_->has_ensured_capacity_ = false;
44 // Make sure the generated instruction doesn't take up more
45 // space than the minimum gap.
46 int delta = gap_ - ComputeGap();
47 CHECK(delta <= kMinimumGap);
48}
49#endif
50
51
52AssemblerBuffer::AssemblerBuffer() {
53 static const size_t kInitialBufferCapacity = 4 * KB;
54 contents_ = NewContents(kInitialBufferCapacity);
55 cursor_ = contents_;
56 limit_ = ComputeLimit(contents_, kInitialBufferCapacity);
57 fixup_ = NULL;
58#if defined(DEBUG)
59 has_ensured_capacity_ = false;
60 fixups_processed_ = false;
61#endif
62
63 // Verify internal state.
64 CHECK_EQ(Capacity(), kInitialBufferCapacity);
65 CHECK_EQ(Size(), 0);
66}
67
68
69AssemblerBuffer::~AssemblerBuffer() {
70}
71
72
73void AssemblerBuffer::ProcessFixups(const MemoryRegion& region) {
74 AssemblerFixup* fixup = fixup_;
75 while (fixup != NULL) {
76 fixup->Process(region, fixup->position());
77 fixup = fixup->previous();
78 }
79}
80
81
82void AssemblerBuffer::FinalizeInstructions(const MemoryRegion& instructions) {
83 // Copy the instructions from the buffer.
84 MemoryRegion from(reinterpret_cast<void*>(contents()), Size());
85 instructions.CopyFrom(0, from);
86
87 // Process fixups in the instructions.
88 ProcessFixups(instructions);
89#if defined(DEBUG)
90 fixups_processed_ = true;
91#endif
92}
93
94
95void AssemblerBuffer::ExtendCapacity() {
96 size_t old_size = Size();
97 size_t old_capacity = Capacity();
98 size_t new_capacity = std::min(old_capacity * 2, old_capacity + 1 * MB);
99
100 // Allocate the new data area and copy contents of the old one to it.
101 byte* new_contents = NewContents(new_capacity);
102 memmove(reinterpret_cast<void*>(new_contents),
103 reinterpret_cast<void*>(contents_),
104 old_size);
105
106 // Compute the relocation delta and switch to the new contents area.
107 ptrdiff_t delta = new_contents - contents_;
108 contents_ = new_contents;
109
110 // Update the cursor and recompute the limit.
111 cursor_ += delta;
112 limit_ = ComputeLimit(new_contents, new_capacity);
113
114 // Verify internal state.
115 CHECK_EQ(Capacity(), new_capacity);
116 CHECK_EQ(Size(), old_size);
117}
118
119
120#if 0
121// Shared macros are implemented here.
122void Assembler::Unimplemented(const char* message) {
123 Stop("unimplemented");
124}
125
126
127void Assembler::Untested(const char* message) {
128 Stop("untested");
129}
130
131
132void Assembler::Unreachable(const char* message) {
133 Stop("unreachable");
134}
135#endif
136
137} } // namespace android::runtime