blob: dfee8115ee09e487a790f566fc525a791e001640 [file] [log] [blame]
Elliott Hughes2faa5f12012-01-30 14:42:07 -08001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070016
Ian Rogers2c8f6532011-09-02 17:16:34 -070017#include "assembler.h"
18
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070019#include <algorithm>
20#include <vector>
Ian Rogers2c8f6532011-09-02 17:16:34 -070021
22#include "assembler_arm.h"
23#include "assembler_x86.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070024#include "globals.h"
25#include "memory_region.h"
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070026
Carl Shapiro6b6b5f02011-06-21 15:05:09 -070027namespace art {
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070028
29static byte* NewContents(size_t capacity) {
30 byte* result = new byte[capacity];
31#if defined(DEBUG)
32 // Initialize the buffer with kBreakPointInstruction to force a break
33 // point if we ever execute an uninitialized part of the code buffer.
34 Assembler::InitializeMemoryWithBreakpoints(result, capacity);
35#endif
36 return result;
37}
38
39
40#if defined(DEBUG)
41AssemblerBuffer::EnsureCapacity::EnsureCapacity(AssemblerBuffer* buffer) {
42 if (buffer->cursor() >= buffer->limit()) buffer->ExtendCapacity();
43 // In debug mode, we save the assembler buffer along with the gap
44 // size before we start emitting to the buffer. This allows us to
45 // check that any single generated instruction doesn't overflow the
46 // limit implied by the minimum gap size.
47 buffer_ = buffer;
48 gap_ = ComputeGap();
49 // Make sure that extending the capacity leaves a big enough gap
50 // for any kind of instruction.
Ian Rogersb033c752011-07-20 12:22:35 -070051 CHECK_GE(gap_, kMinimumGap);
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070052 // Mark the buffer as having ensured the capacity.
53 CHECK(!buffer->HasEnsuredCapacity()); // Cannot nest.
54 buffer->has_ensured_capacity_ = true;
55}
56
57
58AssemblerBuffer::EnsureCapacity::~EnsureCapacity() {
59 // Unmark the buffer, so we cannot emit after this.
60 buffer_->has_ensured_capacity_ = false;
61 // Make sure the generated instruction doesn't take up more
62 // space than the minimum gap.
63 int delta = gap_ - ComputeGap();
Ian Rogersb033c752011-07-20 12:22:35 -070064 CHECK_LE(delta, kMinimumGap);
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070065}
66#endif
67
68
69AssemblerBuffer::AssemblerBuffer() {
70 static const size_t kInitialBufferCapacity = 4 * KB;
71 contents_ = NewContents(kInitialBufferCapacity);
72 cursor_ = contents_;
73 limit_ = ComputeLimit(contents_, kInitialBufferCapacity);
74 fixup_ = NULL;
Ian Rogers45a76cb2011-07-21 22:00:15 -070075 slow_path_ = NULL;
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070076#if defined(DEBUG)
77 has_ensured_capacity_ = false;
78 fixups_processed_ = false;
79#endif
80
81 // Verify internal state.
82 CHECK_EQ(Capacity(), kInitialBufferCapacity);
Elliott Hughes1f359b02011-07-17 14:27:17 -070083 CHECK_EQ(Size(), 0U);
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070084}
85
86
87AssemblerBuffer::~AssemblerBuffer() {
Elliott Hughesc1674ed2011-08-25 18:09:09 -070088 delete[] contents_;
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -070089}
90
91
92void AssemblerBuffer::ProcessFixups(const MemoryRegion& region) {
93 AssemblerFixup* fixup = fixup_;
94 while (fixup != NULL) {
95 fixup->Process(region, fixup->position());
96 fixup = fixup->previous();
97 }
98}
99
100
101void AssemblerBuffer::FinalizeInstructions(const MemoryRegion& instructions) {
102 // Copy the instructions from the buffer.
103 MemoryRegion from(reinterpret_cast<void*>(contents()), Size());
104 instructions.CopyFrom(0, from);
Carl Shapiroa5d5cfd2011-06-21 12:46:59 -0700105 // Process fixups in the instructions.
106 ProcessFixups(instructions);
107#if defined(DEBUG)
108 fixups_processed_ = true;
109#endif
110}
111
112
113void AssemblerBuffer::ExtendCapacity() {
114 size_t old_size = Size();
115 size_t old_capacity = Capacity();
116 size_t new_capacity = std::min(old_capacity * 2, old_capacity + 1 * MB);
117
118 // Allocate the new data area and copy contents of the old one to it.
119 byte* new_contents = NewContents(new_capacity);
120 memmove(reinterpret_cast<void*>(new_contents),
121 reinterpret_cast<void*>(contents_),
122 old_size);
123
124 // Compute the relocation delta and switch to the new contents area.
125 ptrdiff_t delta = new_contents - contents_;
126 contents_ = new_contents;
127
128 // Update the cursor and recompute the limit.
129 cursor_ += delta;
130 limit_ = ComputeLimit(new_contents, new_capacity);
131
132 // Verify internal state.
133 CHECK_EQ(Capacity(), new_capacity);
134 CHECK_EQ(Size(), old_size);
135}
136
Ian Rogers2c8f6532011-09-02 17:16:34 -0700137
138Assembler* Assembler::Create(InstructionSet instruction_set) {
139 if (instruction_set == kX86) {
140 return new x86::X86Assembler();
141 } else {
142 CHECK(instruction_set == kArm || instruction_set == kThumb2);
143 return new arm::ArmAssembler();
144 }
145}
146
Carl Shapiro6b6b5f02011-06-21 15:05:09 -0700147} // namespace art