Mercurial > hg > truffle
comparison graal/com.oracle.max.asmdis/src/com/sun/max/asm/Assembler.java @ 3733:e233f5660da4
Added Java files from Maxine project.
author | Thomas Wuerthinger <thomas.wuerthinger@oracle.com> |
---|---|
date | Sat, 17 Dec 2011 19:59:18 +0100 |
parents | |
children | bc8527f3071c |
comparison
equal
deleted
inserted
replaced
3732:3e2e8b8abdaf | 3733:e233f5660da4 |
---|---|
1 /* | |
2 * Copyright (c) 2007, 2011, 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.sun.max.asm; | |
24 | |
25 import java.io.*; | |
26 import java.util.*; | |
27 | |
28 import com.sun.max.lang.*; | |
29 import com.sun.max.program.*; | |
30 | |
31 /** | |
32 * Assembler base class. | |
33 */ | |
34 public abstract class Assembler { | |
35 | |
36 private final Directives directives; | |
37 | |
38 protected Assembler(byte byteData, boolean isValidCode) { | |
39 this.directives = new Directives(byteData, isValidCode); | |
40 } | |
41 | |
42 public abstract ISA isa(); | |
43 | |
44 public final Directives directives() { | |
45 return directives; | |
46 } | |
47 | |
48 /** | |
49 * Gets the width of a word on machine for which the code is being assembled. | |
50 */ | |
51 public abstract WordWidth wordWidth(); | |
52 | |
53 /** | |
54 * Resets any internal state in this assembler to the equivalent state it had when first constructed. | |
55 * <p> | |
56 * This method is overridden as needed to ensure the state in subclasses is reset as well. Any | |
57 * overriding implementation must call this method in its superclass. | |
58 */ | |
59 public Assembler reset() { | |
60 boundLabels.clear(); | |
61 assembledObjects.clear(); | |
62 mutableAssembledObjects.clear(); | |
63 padOutput = false; | |
64 potentialExpansionSize = 0; | |
65 selectingLabelInstructions = true; | |
66 stream.reset(); | |
67 if (this instanceof Assembler32) { | |
68 final Assembler32 assembler32 = (Assembler32) this; | |
69 assembler32.setStartAddress(0); | |
70 } else if (this instanceof Assembler64) { | |
71 final Assembler64 assembler64 = (Assembler64) this; | |
72 assembler64.setStartAddress(0); | |
73 } | |
74 return this; | |
75 } | |
76 | |
77 /** | |
78 * A facility for including output during assembly that may not necessarily be decoded interpreted as code. | |
79 * | |
80 */ | |
81 public final class Directives { | |
82 | |
83 private final byte padByte; | |
84 private final boolean isValidCode; | |
85 | |
86 public Directives(byte padByte, boolean isValidCode) { | |
87 this.padByte = padByte; | |
88 this.isValidCode = isValidCode; | |
89 } | |
90 /** | |
91 * Inserts as many {@linkplain #padByte pad bytes} as necessary to ensure that the next assembled object starts | |
92 * at an address aligned by a given number. | |
93 * | |
94 * @param alignment | |
95 * the next assembled object is guaranteed to start at the next highest address starting at the | |
96 * current address that is divisible by this value. Note that this computed address will be the | |
97 * current address if the current address is already aligned by {@code alignment} | |
98 */ | |
99 private void alignIfSpaceLeftSmallerThan(int alignment, int requiredSpace, int alignmentStart) { | |
100 final int startPosition = currentPosition(); | |
101 | |
102 // We avoid sign problems with '%' below by masking off the sign bit: | |
103 final long unsignedAddend = (baseAddress() + startPosition + alignmentStart) & Long.MAX_VALUE; | |
104 | |
105 final int misalignmentSize = (int) (unsignedAddend % alignment); | |
106 final int padSize = misalignmentSize > 0 ? (alignment - misalignmentSize) : 0; | |
107 for (int i = 0; i < padSize; i++) { | |
108 emitByte(padByte); | |
109 } | |
110 new AlignmentPadding(Assembler.this, startPosition, currentPosition(), alignment, alignmentStart, requiredSpace, padByte) { | |
111 public boolean isCode() { | |
112 return isValidCode; | |
113 } | |
114 }; | |
115 } | |
116 | |
117 public void align(int alignment) { | |
118 alignIfSpaceLeftSmallerThan(alignment, alignment, 0); | |
119 } | |
120 | |
121 /** | |
122 * Enforce that the next assembled object fits within an aligned chunk. | |
123 * The specified space required by the next assembled object must be smaller or equals to the specified alignment. If the object cannot fit in the current chunk, | |
124 * Inserts as many {@linkplain #padByte pad bytes} as necessary to ensure that the next assembled object starts | |
125 * at the next alignment. | |
126 * | |
127 * @param alignment | |
128 * the next assembled object is guaranteed to fit in within a block of memory whose starting address is the next | |
129 * address starting at the | |
130 * current address that is divisible by this value. | |
131 * @param requiredSpace size of the next assembled object; it must be smaller or equals to alignment | |
132 */ | |
133 public boolean align(int alignment, int requiredSpace) { | |
134 if (alignment < requiredSpace) { | |
135 return false; | |
136 } | |
137 alignIfSpaceLeftSmallerThan(alignment, requiredSpace, 0); | |
138 return true; | |
139 } | |
140 | |
141 /** | |
142 * Inserts as many {@linkplain #padByte pad bytes} as necessary to ensure that the nth byte within the next assembled object starts | |
143 * at an address aligned by a given number. | |
144 * @param alignment | |
145 * @param alignmentStart where the alignment should start within the next assembled object. | |
146 */ | |
147 public void alignAfter(int alignment, int alignmentStart) { | |
148 alignIfSpaceLeftSmallerThan(alignment, alignment, alignmentStart); | |
149 } | |
150 | |
151 public void inlineByte(byte byteValue) { | |
152 addInlineData(currentPosition(), Bytes.SIZE); | |
153 emitByte(byteValue); | |
154 } | |
155 | |
156 public void inlineByteArray(byte[] byteArrayValue) { | |
157 addInlineData(currentPosition(), byteArrayValue.length); | |
158 emitByteArray(byteArrayValue, 0, byteArrayValue.length); | |
159 } | |
160 | |
161 public void inlineByteArray(byte[] byteArrayValue, int offset, int length) { | |
162 addInlineData(currentPosition(), length); | |
163 emitByteArray(byteArrayValue, offset, length); | |
164 } | |
165 | |
166 public void inlineShort(short shortValue) { | |
167 addInlineData(currentPosition(), Shorts.SIZE); | |
168 emitShort(shortValue); | |
169 } | |
170 | |
171 public void inlineInt(int intValue) { | |
172 addInlineData(currentPosition(), Ints.SIZE); | |
173 emitInt(intValue); | |
174 } | |
175 | |
176 public void inlineLong(long longValue) { | |
177 addInlineData(currentPosition(), Longs.SIZE); | |
178 emitLong(longValue); | |
179 } | |
180 | |
181 /** | |
182 * Inlines the absolute address of a position (represented by a given label) in the assembled code. | |
183 * The absolute address is calculated as {@code baseAddress() + label.position()}. The size | |
184 * of the inlined address is determined by {@link Assembler#wordWidth()}. | |
185 * | |
186 * @param label the label whose absolute address is to be inlined | |
187 */ | |
188 public AddressLiteral inlineAddress(Label label) { | |
189 final int startPosition = currentPosition(); | |
190 // Emit placeholder bytes | |
191 final WordWidth width = wordWidth(); | |
192 for (int i = 0; i < width.numberOfBytes; i++) { | |
193 emitByte((byte) 0); | |
194 } | |
195 final AddressLiteral addressLiteral = new AddressLiteral(Assembler.this, startPosition, currentPosition(), label); | |
196 assert addressLiteral.size() == width.numberOfBytes; | |
197 return addressLiteral; | |
198 } | |
199 | |
200 /** | |
201 * Inlines the offset between two positions (represented by given labels) in the assembled code. | |
202 * | |
203 * @param base the label whose position marks the base of the offset | |
204 * @param target the label whose position marks the target of the offset | |
205 * @param width the fixed size to be used for the offset | |
206 */ | |
207 public OffsetLiteral inlineOffset(Label target, Label base, WordWidth width) { | |
208 final int startPosition = currentPosition(); | |
209 for (int i = 0; i < width.numberOfBytes; i++) { | |
210 emitByte((byte) 0); | |
211 } | |
212 final OffsetLiteral offsetLiteral = new OffsetLiteral(Assembler.this, startPosition, currentPosition(), target, base); | |
213 assert offsetLiteral.size() == width.numberOfBytes; | |
214 return offsetLiteral; | |
215 } | |
216 } | |
217 | |
218 /** | |
219 * Gets the number of bytes that have been written to the underlying output stream. | |
220 */ | |
221 public int currentPosition() { | |
222 return stream.size(); | |
223 } | |
224 | |
225 /** | |
226 * Gets the start address of the code assembled by this assembler. | |
227 */ | |
228 public abstract long baseAddress(); | |
229 | |
230 private ByteArrayOutputStream stream = new ByteArrayOutputStream(); | |
231 | |
232 protected void emitByte(int byteValue) { | |
233 stream.write(byteValue); | |
234 } | |
235 | |
236 protected void emitZeroes(int count) { | |
237 for (int i = 0; i < count; ++i) { | |
238 stream.write(0); | |
239 } | |
240 } | |
241 | |
242 protected abstract void emitShort(short shortValue); | |
243 | |
244 protected abstract void emitInt(int intValue); | |
245 | |
246 protected abstract void emitLong(long longValue); | |
247 | |
248 public void emitByteArray(byte[] byteArrayValue, int off, int len) { | |
249 stream.write(byteArrayValue, off, len); | |
250 } | |
251 | |
252 private boolean selectingLabelInstructions = true; | |
253 | |
254 boolean selectingLabelInstructions() { | |
255 return selectingLabelInstructions; | |
256 } | |
257 | |
258 private final Set<Label> boundLabels = Collections.newSetFromMap(new IdentityHashMap<Label, Boolean>()); | |
259 | |
260 public Set<Label> boundLabels() { | |
261 return boundLabels; | |
262 } | |
263 | |
264 /** | |
265 * Binds a given label to the current position in the assembler's instruction stream. The assembler may update the | |
266 * label's position if any emitted instructions change lengths, so that this label keeps addressing the same logical | |
267 * position. | |
268 * | |
269 * @param label | |
270 * the label that is to be bound to the current position | |
271 * | |
272 * @see Label#fix32 | |
273 */ | |
274 public final void bindLabel(Label label) { | |
275 label.bind(currentPosition()); | |
276 boundLabels.add(label); | |
277 } | |
278 | |
279 private final List<AssembledObject> assembledObjects = new LinkedList<AssembledObject>(); | |
280 private final List<MutableAssembledObject> mutableAssembledObjects = new LinkedList<MutableAssembledObject>(); | |
281 | |
282 private int potentialExpansionSize; | |
283 | |
284 /** | |
285 * Adds the description of an instruction that is fixed in size. | |
286 * | |
287 * @param fixedSizeAssembledObject | |
288 */ | |
289 void addFixedSizeAssembledObject(AssembledObject fixedSizeAssembledObject) { | |
290 assembledObjects.add(fixedSizeAssembledObject); | |
291 if (fixedSizeAssembledObject instanceof MutableAssembledObject) { | |
292 mutableAssembledObjects.add((MutableAssembledObject) fixedSizeAssembledObject); | |
293 } | |
294 } | |
295 | |
296 /** | |
297 * Adds the description of an instruction that can change in size, depending on where it is located in the | |
298 * instruction and/or where another object it addresses is located in the instruction stream. | |
299 * | |
300 * @param spanDependentInstruction | |
301 */ | |
302 void addSpanDependentInstruction(InstructionWithOffset spanDependentInstruction) { | |
303 assembledObjects.add(spanDependentInstruction); | |
304 mutableAssembledObjects.add(spanDependentInstruction); | |
305 // A span-dependent instruction's offset operand can potentially grow from 8 bits to 32 bits. | |
306 // Also, some instructions need an extra byte for encoding when not using an 8-bit operand. | |
307 // Together, this might enlarge every span-dependent label instruction by maximally 4 bytes. | |
308 potentialExpansionSize += 4; | |
309 } | |
310 | |
311 void addAlignmentPadding(AlignmentPadding alignmentPadding) { | |
312 assembledObjects.add(alignmentPadding); | |
313 mutableAssembledObjects.add(alignmentPadding); | |
314 potentialExpansionSize += alignmentPadding.alignment() - alignmentPadding.size(); | |
315 } | |
316 | |
317 void addInlineData(int startPosition, int size) { | |
318 assembledObjects.add(new AssembledObject(startPosition, startPosition + size) { | |
319 public boolean isCode() { | |
320 return false; | |
321 } | |
322 }); | |
323 } | |
324 | |
325 private void gatherLabels() throws AssemblyException { | |
326 for (AssembledObject assembledObject : assembledObjects) { | |
327 if (assembledObject instanceof InstructionWithLabel) { | |
328 final InstructionWithLabel labelInstruction = (InstructionWithLabel) assembledObject; | |
329 switch (labelInstruction.label().state()) { | |
330 case UNASSIGNED: | |
331 throw new AssemblyException("unassigned label"); | |
332 case BOUND: | |
333 boundLabels.add(labelInstruction.label()); | |
334 break; | |
335 default: | |
336 break; | |
337 } | |
338 } | |
339 } | |
340 } | |
341 | |
342 private boolean updateSpanDependentInstruction(InstructionWithOffset instruction) throws AssemblyException { | |
343 if (!instruction.updateLabelSize()) { | |
344 return false; | |
345 } | |
346 final int oldSize = instruction.size(); | |
347 final int oldEndPosition = instruction.endPosition(); | |
348 stream.reset(); | |
349 instruction.assemble(); | |
350 final int newSize = stream.toByteArray().length; | |
351 instruction.setSize(newSize); | |
352 final int delta = newSize - oldSize; | |
353 adjustMutableAssembledObjects(delta, oldEndPosition, null); | |
354 return true; | |
355 } | |
356 | |
357 private boolean updateAlignmentPadding(AlignmentPadding alignmentPadding) throws AssemblyException { | |
358 final int oldSize = alignmentPadding.size(); | |
359 final int oldEndPosition = alignmentPadding.endPosition(); | |
360 alignmentPadding.updatePadding(); | |
361 final int newSize = alignmentPadding.size(); | |
362 if (oldSize != newSize) { | |
363 // Only if the padding expanded will subsequent objects in the stream need to be adjusted | |
364 final int delta = newSize - oldSize; | |
365 adjustMutableAssembledObjects(delta, oldEndPosition, alignmentPadding); | |
366 return true; | |
367 } | |
368 return false; | |
369 } | |
370 | |
371 /** | |
372 * Adjusts the position of all the mutable objects that are currently at or after a given position. | |
373 * | |
374 * @param delta the amount by which the position of each mutable object is to be adjusted | |
375 * @param startPosition only mutable objects whose current {@linkplain AssembledObject#startPosition() start | |
376 * position} is equal to or greater than this value are adjusted | |
377 * @param adjustedPadding the padding object whose adjustment caused the need for this call. If this call was made | |
378 * for some other reason than having adjusted a padding object's size, then this value will be null. In this | |
379 * value is not null, then its position will not be adjusted by this call. | |
380 */ | |
381 private void adjustMutableAssembledObjects(int delta, int startPosition, AlignmentPadding adjustedPadding) throws AssemblyException { | |
382 for (Label label : boundLabels) { | |
383 if (label.position() >= startPosition) { | |
384 label.adjust(delta); | |
385 } | |
386 } | |
387 | |
388 for (MutableAssembledObject mutableAssembledObject : mutableAssembledObjects) { | |
389 if (mutableAssembledObject != adjustedPadding && mutableAssembledObject.startPosition() >= startPosition) { | |
390 mutableAssembledObject.adjust(delta); | |
391 } | |
392 } | |
393 } | |
394 | |
395 private void updateSpanDependentVariableInstructions() throws AssemblyException { | |
396 boolean changed; | |
397 do { | |
398 changed = false; | |
399 for (MutableAssembledObject mutableAssembledObject : mutableAssembledObjects) { | |
400 if (mutableAssembledObject instanceof InstructionWithOffset) { | |
401 changed |= updateSpanDependentInstruction((InstructionWithOffset) mutableAssembledObject); | |
402 } else if (mutableAssembledObject instanceof AlignmentPadding) { | |
403 changed |= updateAlignmentPadding((AlignmentPadding) mutableAssembledObject); | |
404 } | |
405 } | |
406 } while (changed); | |
407 } | |
408 | |
409 private int writeOutput(OutputStream outputStream, byte[] initialBytes, InlineDataRecorder inlineDataRecorder) throws IOException, AssemblyException { | |
410 selectingLabelInstructions = false; | |
411 int bytesWritten = 0; | |
412 try { | |
413 int initialOffset = 0; | |
414 for (AssembledObject assembledObject : assembledObjects) { | |
415 if (inlineDataRecorder != null && !assembledObject.isCode()) { | |
416 inlineDataRecorder.add(new InlineDataDescriptor.ByteData(assembledObject.startPosition(), assembledObject.size())); | |
417 } | |
418 | |
419 if (assembledObject instanceof MutableAssembledObject) { | |
420 final MutableAssembledObject mutableAssembledObject = (MutableAssembledObject) assembledObject; | |
421 | |
422 // Copy the original assembler output between the end of the last mutable assembled object and the start of the current one | |
423 final int length = mutableAssembledObject.initialStartPosition() - initialOffset; | |
424 outputStream.write(initialBytes, initialOffset, length); | |
425 bytesWritten += length; | |
426 | |
427 // Now (re)assemble the mutable assembled object | |
428 stream.reset(); | |
429 mutableAssembledObject.assemble(); | |
430 stream.writeTo(outputStream); | |
431 bytesWritten += stream.size(); | |
432 initialOffset = mutableAssembledObject.initialEndPosition(); | |
433 } else { | |
434 // Copy the original assembler output between the end of the last assembled object and the end of current one | |
435 final int length = assembledObject.endPosition() - initialOffset; | |
436 outputStream.write(initialBytes, initialOffset, length); | |
437 bytesWritten += length; | |
438 initialOffset = assembledObject.endPosition(); | |
439 } | |
440 } | |
441 | |
442 // Copy the original assembler output (if any) after the last mutable assembled object | |
443 outputStream.write(initialBytes, initialOffset, initialBytes.length - initialOffset); | |
444 bytesWritten += initialBytes.length - initialOffset; | |
445 | |
446 if (padOutput) { | |
447 final int padding = (initialBytes.length + potentialExpansionSize) - bytesWritten; | |
448 assert padding >= 0; | |
449 if (padding > 0) { | |
450 stream.reset(); | |
451 emitPadding(padding); | |
452 stream.writeTo(outputStream); | |
453 bytesWritten += padding; | |
454 } | |
455 } | |
456 return bytesWritten; | |
457 } finally { | |
458 selectingLabelInstructions = true; | |
459 } | |
460 } | |
461 | |
462 /** | |
463 * Emits padding to the instruction stream in the form of NOP instructions. | |
464 * | |
465 * @param numberOfBytes | |
466 * @throws AssemblyException if exactly {@code numberOfBytes} cannot be emitted as a sequence of one or more valid NOP instructions | |
467 */ | |
468 protected abstract void emitPadding(int numberOfBytes) throws AssemblyException; | |
469 | |
470 /** | |
471 * Writes the object code assembled so far to a given output stream. | |
472 * | |
473 * @return the number of bytes written {@code outputStream} | |
474 * @throws AssemblyException | |
475 * if there any problem with binding labels to addresses | |
476 */ | |
477 public int output(OutputStream outputStream, InlineDataRecorder inlineDataRecorder) throws IOException, AssemblyException { | |
478 final int upperLimitForCurrentOutputSize = upperLimitForCurrentOutputSize(); | |
479 final byte[] initialBytes = stream.toByteArray(); | |
480 gatherLabels(); | |
481 updateSpanDependentVariableInstructions(); | |
482 final int bytesWritten = writeOutput(outputStream, initialBytes, inlineDataRecorder); | |
483 assert !padOutput || upperLimitForCurrentOutputSize == bytesWritten; | |
484 return bytesWritten; | |
485 } | |
486 | |
487 /** | |
488 * Gets the maximum size of the code array that would be assembled by a call to {@link #output(OutputStream)} or | |
489 * {@link #toByteArray()}. For a variable sized instruction set (e.g. x86), the exact size may be known until the | |
490 * code is assembled as the size of certain instructions depends on their position in the instruction and/or the | |
491 * {@linkplain #baseAddress() base address} at which the code is being assembled. | |
492 * <p> | |
493 * <b>Note that any subsequent call that adds a new instruction to the instruction stream invalidates the value | |
494 * returned by this method.</b> | |
495 */ | |
496 public int upperLimitForCurrentOutputSize() { | |
497 return currentPosition() + potentialExpansionSize; | |
498 } | |
499 | |
500 private boolean padOutput; | |
501 | |
502 /** | |
503 * Sets or unsets the flag determining if the code assembled by a call to {@link #output(OutputStream)} or | |
504 * {@link #toByteArray()} should be padded with NOPs at the end to ensure that the code size equals the value | |
505 * returned by {@link #upperLimitForCurrentOutputSize()}. This default value of the flag is {@code false}. | |
506 */ | |
507 public void setPadOutput(boolean flag) { | |
508 padOutput = flag; | |
509 } | |
510 | |
511 /** | |
512 * Returns the object code assembled so far in a byte array. | |
513 * | |
514 * @throws AssemblyException | |
515 * if there any problem with binding labels to addresses | |
516 */ | |
517 public byte[] toByteArray(InlineDataRecorder inlineDataRecorder) throws AssemblyException { | |
518 final ByteArrayOutputStream baos = new ByteArrayOutputStream(upperLimitForCurrentOutputSize()); | |
519 try { | |
520 output(baos, inlineDataRecorder); | |
521 baos.close(); | |
522 final byte[] result = baos.toByteArray(); | |
523 return result; | |
524 } catch (IOException ioException) { | |
525 throw ProgramError.unexpected("IOException during output to byte array", ioException); | |
526 } | |
527 } | |
528 | |
529 public byte[] toByteArray() throws AssemblyException { | |
530 return toByteArray(null); | |
531 } | |
532 | |
533 /** | |
534 * @see Label#fix32(int) | |
535 */ | |
536 protected void fixLabel32(Label label, int address32) { | |
537 label.fix32(address32); | |
538 } | |
539 | |
540 /** | |
541 * @see Label#fix64(long) | |
542 */ | |
543 protected void fixLabel64(Label label, long address64) { | |
544 label.fix64(address64); | |
545 } | |
546 | |
547 protected int address32(Label label) throws AssemblyException { | |
548 return label.address32(); | |
549 } | |
550 | |
551 protected long address64(Label label) throws AssemblyException { | |
552 return label.address64(); | |
553 } | |
554 | |
555 protected void checkConstraint(boolean passed, String expression) { | |
556 if (!passed) { | |
557 throw new IllegalArgumentException(expression); | |
558 } | |
559 } | |
560 | |
561 /** | |
562 * Calculate the difference between two Labels. This works whether the labels | |
563 * are fixed or bound. | |
564 * @throws AssemblyException | |
565 */ | |
566 public int labelOffsetRelative(Label label, Label relativeTo) throws AssemblyException { | |
567 return labelOffsetRelative(label, 0) - labelOffsetRelative(relativeTo, 0); | |
568 } | |
569 | |
570 /** | |
571 * Calculate the difference between a Label and a position within the assembled code. | |
572 * @throws AssemblyException | |
573 */ | |
574 public int labelOffsetRelative(Label label, int position) throws AssemblyException { | |
575 switch (label.state()) { | |
576 case BOUND: { | |
577 return label.position() - position; | |
578 } | |
579 case FIXED_32: { | |
580 final Assembler32 assembler32 = (Assembler32) this; | |
581 return assembler32.address(label) - (assembler32.startAddress() + position); | |
582 } | |
583 case FIXED_64: { | |
584 final Assembler64 assembler64 = (Assembler64) this; | |
585 final long offset64 = assembler64.address(label) - (assembler64.startAddress() + position); | |
586 if (Longs.numberOfEffectiveSignedBits(offset64) > 32) { | |
587 throw new AssemblyException("fixed 64-bit label out of 32-bit range"); | |
588 } | |
589 return (int) offset64; | |
590 } | |
591 default: { | |
592 throw new AssemblyException("unassigned label"); | |
593 } | |
594 } | |
595 } | |
596 | |
597 /** | |
598 * Calculate the difference between a Label and an assembled object. | |
599 * Different CPUs have different conventions for which end of an | |
600 * instruction to measure from. | |
601 * @throws AssemblyException | |
602 */ | |
603 public final int offsetInstructionRelative(Label label, AssemblyObject assembledObject) throws AssemblyException { | |
604 final int position = (isa().relativeBranchFromStart) ? assembledObject.startPosition() : assembledObject.endPosition(); | |
605 return labelOffsetRelative(label, position); | |
606 } | |
607 } |