blob: 9e67f12fc837ccba33770d50c0bc8e1799cc0fd6 [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>
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07005#include "assembler.h"
6#include "globals.h"
7#include "memory_region.h"
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -07008
Carl Shapiro6b6b5f02011-06-21 15:05:09 -07009namespace art {
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070010
11static byte* NewContents(size_t capacity) {
12 byte* result = new byte[capacity];
13#if defined(DEBUG)
14 // Initialize the buffer with kBreakPointInstruction to force a break
15 // point if we ever execute an uninitialized part of the code buffer.
16 Assembler::InitializeMemoryWithBreakpoints(result, capacity);
17#endif
18 return result;
19}
20
21
22#if defined(DEBUG)
23AssemblerBuffer::EnsureCapacity::EnsureCapacity(AssemblerBuffer* buffer) {
24 if (buffer->cursor() >= buffer->limit()) buffer->ExtendCapacity();
25 // In debug mode, we save the assembler buffer along with the gap
26 // size before we start emitting to the buffer. This allows us to
27 // check that any single generated instruction doesn't overflow the
28 // limit implied by the minimum gap size.
29 buffer_ = buffer;
30 gap_ = ComputeGap();
31 // Make sure that extending the capacity leaves a big enough gap
32 // for any kind of instruction.
Ian Rogersb033c752011-07-20 12:22:35 -070033 CHECK_GE(gap_, kMinimumGap);
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070034 // Mark the buffer as having ensured the capacity.
35 CHECK(!buffer->HasEnsuredCapacity()); // Cannot nest.
36 buffer->has_ensured_capacity_ = true;
37}
38
39
40AssemblerBuffer::EnsureCapacity::~EnsureCapacity() {
41 // Unmark the buffer, so we cannot emit after this.
42 buffer_->has_ensured_capacity_ = false;
43 // Make sure the generated instruction doesn't take up more
44 // space than the minimum gap.
45 int delta = gap_ - ComputeGap();
Ian Rogersb033c752011-07-20 12:22:35 -070046 CHECK_LE(delta, kMinimumGap);
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070047}
48#endif
49
50
51AssemblerBuffer::AssemblerBuffer() {
52 static const size_t kInitialBufferCapacity = 4 * KB;
53 contents_ = NewContents(kInitialBufferCapacity);
54 cursor_ = contents_;
55 limit_ = ComputeLimit(contents_, kInitialBufferCapacity);
56 fixup_ = NULL;
Ian Rogers45a76cb2011-07-21 22:00:15 -070057 slow_path_ = NULL;
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070058#if defined(DEBUG)
59 has_ensured_capacity_ = false;
60 fixups_processed_ = false;
61#endif
62
63 // Verify internal state.
64 CHECK_EQ(Capacity(), kInitialBufferCapacity);
Elliott Hughes1f359b02011-07-17 14:27:17 -070065 CHECK_EQ(Size(), 0U);
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070066}
67
68
69AssemblerBuffer::~AssemblerBuffer() {
Elliott Hughesc1674ed2011-08-25 18:09:09 -070070 delete[] contents_;
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070071}
72
73
74void AssemblerBuffer::ProcessFixups(const MemoryRegion& region) {
75 AssemblerFixup* fixup = fixup_;
76 while (fixup != NULL) {
77 fixup->Process(region, fixup->position());
78 fixup = fixup->previous();
79 }
80}
81
82
83void AssemblerBuffer::FinalizeInstructions(const MemoryRegion& instructions) {
84 // Copy the instructions from the buffer.
85 MemoryRegion from(reinterpret_cast<void*>(contents()), Size());
86 instructions.CopyFrom(0, from);
Carl Shapiroe2d373e2011-07-25 15:20:06 -070087 // Flush instruction cache
88 __builtin___clear_cache(instructions.start(), instructions.end());
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070089 // Process fixups in the instructions.
90 ProcessFixups(instructions);
91#if defined(DEBUG)
92 fixups_processed_ = true;
93#endif
94}
95
96
97void AssemblerBuffer::ExtendCapacity() {
98 size_t old_size = Size();
99 size_t old_capacity = Capacity();
100 size_t new_capacity = std::min(old_capacity * 2, old_capacity + 1 * MB);
101
102 // Allocate the new data area and copy contents of the old one to it.
103 byte* new_contents = NewContents(new_capacity);
104 memmove(reinterpret_cast<void*>(new_contents),
105 reinterpret_cast<void*>(contents_),
106 old_size);
107
108 // Compute the relocation delta and switch to the new contents area.
109 ptrdiff_t delta = new_contents - contents_;
110 contents_ = new_contents;
111
112 // Update the cursor and recompute the limit.
113 cursor_ += delta;
114 limit_ = ComputeLimit(new_contents, new_capacity);
115
116 // Verify internal state.
117 CHECK_EQ(Capacity(), new_capacity);
118 CHECK_EQ(Size(), old_size);
119}
120
Carl Shapiro6b6b5f02011-06-21 15:05:09 -0700121} // namespace art