blob: d97cf5cf256d0209604110f2284fc33d2181d039 [file] [log] [blame]
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -07001// Copyright 2011 Google Inc. All Rights Reserved.
2
Ian Rogers2c8f6532011-09-02 17:16:34 -07003#include "assembler.h"
4
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -07005#include <algorithm>
6#include <vector>
Ian Rogers2c8f6532011-09-02 17:16:34 -07007
8#include "assembler_arm.h"
9#include "assembler_x86.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070010#include "globals.h"
11#include "memory_region.h"
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070012
Carl Shapiro6b6b5f02011-06-21 15:05:09 -070013namespace art {
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070014
15static byte* NewContents(size_t capacity) {
16 byte* result = new byte[capacity];
17#if defined(DEBUG)
18 // Initialize the buffer with kBreakPointInstruction to force a break
19 // point if we ever execute an uninitialized part of the code buffer.
20 Assembler::InitializeMemoryWithBreakpoints(result, capacity);
21#endif
22 return result;
23}
24
25
26#if defined(DEBUG)
27AssemblerBuffer::EnsureCapacity::EnsureCapacity(AssemblerBuffer* buffer) {
28 if (buffer->cursor() >= buffer->limit()) buffer->ExtendCapacity();
29 // In debug mode, we save the assembler buffer along with the gap
30 // size before we start emitting to the buffer. This allows us to
31 // check that any single generated instruction doesn't overflow the
32 // limit implied by the minimum gap size.
33 buffer_ = buffer;
34 gap_ = ComputeGap();
35 // Make sure that extending the capacity leaves a big enough gap
36 // for any kind of instruction.
Ian Rogersb033c752011-07-20 12:22:35 -070037 CHECK_GE(gap_, kMinimumGap);
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070038 // Mark the buffer as having ensured the capacity.
39 CHECK(!buffer->HasEnsuredCapacity()); // Cannot nest.
40 buffer->has_ensured_capacity_ = true;
41}
42
43
44AssemblerBuffer::EnsureCapacity::~EnsureCapacity() {
45 // Unmark the buffer, so we cannot emit after this.
46 buffer_->has_ensured_capacity_ = false;
47 // Make sure the generated instruction doesn't take up more
48 // space than the minimum gap.
49 int delta = gap_ - ComputeGap();
Ian Rogersb033c752011-07-20 12:22:35 -070050 CHECK_LE(delta, kMinimumGap);
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070051}
52#endif
53
54
55AssemblerBuffer::AssemblerBuffer() {
56 static const size_t kInitialBufferCapacity = 4 * KB;
57 contents_ = NewContents(kInitialBufferCapacity);
58 cursor_ = contents_;
59 limit_ = ComputeLimit(contents_, kInitialBufferCapacity);
60 fixup_ = NULL;
Ian Rogers45a76cb2011-07-21 22:00:15 -070061 slow_path_ = NULL;
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070062#if defined(DEBUG)
63 has_ensured_capacity_ = false;
64 fixups_processed_ = false;
65#endif
66
67 // Verify internal state.
68 CHECK_EQ(Capacity(), kInitialBufferCapacity);
Elliott Hughes1f359b02011-07-17 14:27:17 -070069 CHECK_EQ(Size(), 0U);
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070070}
71
72
73AssemblerBuffer::~AssemblerBuffer() {
Elliott Hughesc1674ed2011-08-25 18:09:09 -070074 delete[] contents_;
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070075}
76
77
78void AssemblerBuffer::ProcessFixups(const MemoryRegion& region) {
79 AssemblerFixup* fixup = fixup_;
80 while (fixup != NULL) {
81 fixup->Process(region, fixup->position());
82 fixup = fixup->previous();
83 }
84}
85
86
87void AssemblerBuffer::FinalizeInstructions(const MemoryRegion& instructions) {
88 // Copy the instructions from the buffer.
89 MemoryRegion from(reinterpret_cast<void*>(contents()), Size());
90 instructions.CopyFrom(0, from);
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070091 // Process fixups in the instructions.
92 ProcessFixups(instructions);
93#if defined(DEBUG)
94 fixups_processed_ = true;
95#endif
96}
97
98
99void AssemblerBuffer::ExtendCapacity() {
100 size_t old_size = Size();
101 size_t old_capacity = Capacity();
102 size_t new_capacity = std::min(old_capacity * 2, old_capacity + 1 * MB);
103
104 // Allocate the new data area and copy contents of the old one to it.
105 byte* new_contents = NewContents(new_capacity);
106 memmove(reinterpret_cast<void*>(new_contents),
107 reinterpret_cast<void*>(contents_),
108 old_size);
109
110 // Compute the relocation delta and switch to the new contents area.
111 ptrdiff_t delta = new_contents - contents_;
112 contents_ = new_contents;
113
114 // Update the cursor and recompute the limit.
115 cursor_ += delta;
116 limit_ = ComputeLimit(new_contents, new_capacity);
117
118 // Verify internal state.
119 CHECK_EQ(Capacity(), new_capacity);
120 CHECK_EQ(Size(), old_size);
121}
122
Ian Rogers2c8f6532011-09-02 17:16:34 -0700123
124Assembler* Assembler::Create(InstructionSet instruction_set) {
125 if (instruction_set == kX86) {
126 return new x86::X86Assembler();
127 } else {
128 CHECK(instruction_set == kArm || instruction_set == kThumb2);
129 return new arm::ArmAssembler();
130 }
131}
132
Carl Shapiro6b6b5f02011-06-21 15:05:09 -0700133} // namespace art