comparison graal/com.oracle.jvmci.code/src/com/oracle/jvmci/code/DataSection.java @ 21556:48c1ebd24120

renamed com.oracle.graal.api[meta|code] modules to com.oracle.jvmci.[meta|code] (JBS:GRAAL-53)
author Doug Simon <doug.simon@oracle.com>
date Wed, 27 May 2015 00:36:16 +0200
parents graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DataSection.java@082417ac43e4
children
comparison
equal deleted inserted replaced
21555:d12eaef9af72 21556:48c1ebd24120
1 /*
2 * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package com.oracle.jvmci.code;
24
25 import com.oracle.jvmci.meta.SerializableConstant;
26 import static com.oracle.jvmci.meta.MetaUtil.*;
27
28 import java.nio.*;
29 import java.util.*;
30 import java.util.function.*;
31
32 import com.oracle.jvmci.code.CompilationResult.DataPatch;
33 import com.oracle.jvmci.code.CompilationResult.DataSectionReference;
34 import com.oracle.jvmci.code.DataSection.Data;
35
36 public final class DataSection implements Iterable<Data> {
37
38 @FunctionalInterface
39 public interface DataBuilder {
40
41 void emit(ByteBuffer buffer, Consumer<DataPatch> patch);
42
43 static DataBuilder raw(byte[] data) {
44 return (buffer, patch) -> buffer.put(data);
45 }
46
47 static DataBuilder serializable(SerializableConstant c) {
48 return (buffer, patch) -> c.serialize(buffer);
49 }
50
51 static DataBuilder zero(int size) {
52 switch (size) {
53 case 1:
54 return (buffer, patch) -> buffer.put((byte) 0);
55 case 2:
56 return (buffer, patch) -> buffer.putShort((short) 0);
57 case 4:
58 return (buffer, patch) -> buffer.putInt(0);
59 case 8:
60 return (buffer, patch) -> buffer.putLong(0L);
61 default:
62 return (buffer, patch) -> {
63 int rest = size;
64 while (rest > 8) {
65 buffer.putLong(0L);
66 rest -= 8;
67 }
68 while (rest > 0) {
69 buffer.put((byte) 0);
70 rest--;
71 }
72 };
73 }
74 }
75 }
76
77 public static final class Data {
78
79 private int alignment;
80 private final int size;
81 private final DataBuilder builder;
82
83 private DataSectionReference ref;
84
85 public Data(int alignment, int size, DataBuilder builder) {
86 this.alignment = alignment;
87 this.size = size;
88 this.builder = builder;
89
90 // initialized in DataSection.insertData(Data)
91 ref = null;
92 }
93
94 public void updateAlignment(int newAlignment) {
95 if (newAlignment == alignment) {
96 return;
97 }
98 alignment = lcm(alignment, newAlignment);
99 }
100
101 public int getAlignment() {
102 return alignment;
103 }
104
105 public int getSize() {
106 return size;
107 }
108
109 public DataBuilder getBuilder() {
110 return builder;
111 }
112
113 @Override
114 public int hashCode() {
115 // Data instances should not be used as hash map keys
116 throw new UnsupportedOperationException("hashCode");
117 }
118
119 @Override
120 public String toString() {
121 return identityHashCodeString(this);
122 }
123
124 @Override
125 public boolean equals(Object obj) {
126 assert ref != null;
127 if (obj == this) {
128 return true;
129 }
130 if (obj instanceof Data) {
131 Data that = (Data) obj;
132 if (this.alignment == that.alignment && this.size == that.size && this.ref.equals(that.ref)) {
133 return true;
134 }
135 }
136 return false;
137 }
138 }
139
140 private final ArrayList<Data> dataItems = new ArrayList<>();
141
142 private boolean finalLayout;
143 private int sectionAlignment;
144 private int sectionSize;
145
146 @Override
147 public int hashCode() {
148 // DataSection instances should not be used as hash map keys
149 throw new UnsupportedOperationException("hashCode");
150 }
151
152 @Override
153 public String toString() {
154 return identityHashCodeString(this);
155 }
156
157 @Override
158 public boolean equals(Object obj) {
159 if (this == obj) {
160 return true;
161 }
162 if (obj instanceof DataSection) {
163 DataSection that = (DataSection) obj;
164 if (this.finalLayout == that.finalLayout && this.sectionAlignment == that.sectionAlignment && this.sectionSize == that.sectionSize && Objects.equals(this.dataItems, that.dataItems)) {
165 return true;
166 }
167 }
168 return false;
169 }
170
171 /**
172 * Insert a {@link Data} item into the data section. If the item is already in the data section,
173 * the same {@link DataSectionReference} is returned.
174 *
175 * @param data the {@link Data} item to be inserted
176 * @return a unique {@link DataSectionReference} identifying the {@link Data} item
177 */
178 public DataSectionReference insertData(Data data) {
179 assert !finalLayout;
180 if (data.ref == null) {
181 data.ref = new DataSectionReference();
182 dataItems.add(data);
183 }
184 return data.ref;
185 }
186
187 /**
188 * Compute the layout of the data section. This can be called only once, and after it has been
189 * called, the data section can no longer be modified.
190 */
191 public void finalizeLayout() {
192 assert !finalLayout;
193 finalLayout = true;
194
195 // simple heuristic: put items with larger alignment requirement first
196 dataItems.sort((a, b) -> a.alignment - b.alignment);
197
198 int position = 0;
199 for (Data d : dataItems) {
200 sectionAlignment = lcm(sectionAlignment, d.alignment);
201 position = align(position, d.alignment);
202
203 d.ref.setOffset(position);
204 position += d.size;
205 }
206
207 sectionSize = position;
208 }
209
210 /**
211 * Get the size of the data section. Can only be called after {@link #finalizeLayout}.
212 */
213 public int getSectionSize() {
214 assert finalLayout;
215 return sectionSize;
216 }
217
218 /**
219 * Get the minimum alignment requirement of the data section. Can only be called after
220 * {@link #finalizeLayout}.
221 */
222 public int getSectionAlignment() {
223 assert finalLayout;
224 return sectionAlignment;
225 }
226
227 /**
228 * Build the data section. Can only be called after {@link #finalizeLayout}.
229 *
230 * @param buffer The {@link ByteBuffer} where the data section should be built. The buffer must
231 * hold at least {@link #getSectionSize()} bytes.
232 * @param patch A {@link Consumer} to receive {@link DataPatch data patches} for relocations in
233 * the data section.
234 */
235 public void buildDataSection(ByteBuffer buffer, Consumer<DataPatch> patch) {
236 assert finalLayout;
237 for (Data d : dataItems) {
238 buffer.position(d.ref.getOffset());
239 d.builder.emit(buffer, patch);
240 }
241 }
242
243 public Data findData(DataSectionReference ref) {
244 for (Data d : dataItems) {
245 if (d.ref == ref) {
246 return d;
247 }
248 }
249 return null;
250 }
251
252 public Iterator<Data> iterator() {
253 return dataItems.iterator();
254 }
255
256 private static int lcm(int x, int y) {
257 if (x == 0) {
258 return y;
259 } else if (y == 0) {
260 return x;
261 }
262
263 int a = Math.max(x, y);
264 int b = Math.min(x, y);
265 while (b > 0) {
266 int tmp = a % b;
267 a = b;
268 b = tmp;
269 }
270
271 int gcd = a;
272 return x * y / gcd;
273 }
274
275 private static int align(int position, int alignment) {
276 return ((position + alignment - 1) / alignment) * alignment;
277 }
278 }