Skip to content

Commit 56374f6

Browse files
committed
[GR-34563] Support jump tables with secondary keys.
PullRequest: graal/10117
2 parents de6c936 + e879e6a commit 56374f6

File tree

9 files changed

+118
-35
lines changed

9 files changed

+118
-35
lines changed

compiler/mx.compiler/suite.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,7 @@
434434
],
435435
"annotationProcessors" : [
436436
],
437+
"spotbugs" : "false",
437438
"checkstyle" : "org.graalvm.compiler.graph",
438439
"javaCompliance" : "8,11+",
439440
"workingSets" : "API,Graal",

compiler/src/org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test/AssemblerTest.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,12 @@ protected InstalledCode assembleMethod(Method m, CodeGenTest test) {
104104
InstalledCode code = backend.addInstalledCode(debug, method, asCompilationRequest(compilationId), compResult);
105105

106106
for (DisassemblerProvider dis : GraalServices.load(DisassemblerProvider.class)) {
107-
String disasm1 = dis.disassembleCompiledCode(options, codeCache, compResult);
108-
Assert.assertTrue(compResult.toString(), disasm1 == null || disasm1.length() > 0);
109-
String disasm2 = dis.disassembleInstalledCode(codeCache, compResult, code);
110-
Assert.assertTrue(code.toString(), disasm2 == null || disasm2.length() > 0);
107+
if (dis.isAvailable(options)) {
108+
String disasm1 = dis.disassembleCompiledCode(options, codeCache, compResult);
109+
Assert.assertTrue(compResult.toString(), disasm1 == null || disasm1.length() > 0);
110+
String disasm2 = dis.disassembleInstalledCode(codeCache, compResult, code);
111+
Assert.assertTrue(code.toString(), disasm2 == null || disasm2.length() > 0);
112+
}
111113
}
112114
return code;
113115
} catch (Throwable e) {

compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ public String toString() {
135135

136136
/**
137137
* Describes a table of signed offsets embedded in the code. The offsets are relative to the
138-
* starting address of the table. This type of table maybe generated when translating a
138+
* starting address of the table. This type of table can be generated when translating a
139139
* multi-way branch based on a key value from a dense value set (e.g. the {@code tableswitch}
140140
* JVM instruction).
141141
*
@@ -144,6 +144,31 @@ public String toString() {
144144
*/
145145
public static final class JumpTable extends CodeAnnotation {
146146

147+
/**
148+
* Constants denoting the format and size of each entry in a jump table.
149+
*/
150+
public enum EntryFormat {
151+
/**
152+
* Each entry is a 4 byte offset. The base of the offset is platform dependent.
153+
*/
154+
OFFSET(4),
155+
156+
/**
157+
* Each entry is a secondary key value followed by a 4 byte offset. The base of the
158+
* offset is platform dependent.
159+
*/
160+
KEY2_OFFSET(8);
161+
162+
EntryFormat(int size) {
163+
this.size = size;
164+
}
165+
166+
/**
167+
* Gets the size of an entry in bytes.
168+
*/
169+
public final int size;
170+
}
171+
147172
/**
148173
* The low value in the key range (inclusive).
149174
*/
@@ -157,13 +182,16 @@ public static final class JumpTable extends CodeAnnotation {
157182
/**
158183
* The size (in bytes) of each table entry.
159184
*/
160-
public final int entrySize;
185+
public final EntryFormat entryFormat;
161186

162-
public JumpTable(int position, int low, int high, int entrySize) {
187+
public JumpTable(int position, int low, int high, EntryFormat entryFormat) {
163188
super(position);
189+
if (high <= low) {
190+
throw new IllegalArgumentException(String.format("low (%d) is not less than high(%d)", low, high));
191+
}
164192
this.low = low;
165193
this.high = high;
166-
this.entrySize = entrySize;
194+
this.entryFormat = entryFormat;
167195
}
168196

169197
@Override
@@ -173,7 +201,7 @@ public boolean equals(Object obj) {
173201
}
174202
if (obj instanceof JumpTable) {
175203
JumpTable that = (JumpTable) obj;
176-
if (this.getPosition() == that.getPosition() && this.entrySize == that.entrySize && this.low == that.low && this.high == that.high) {
204+
if (this.getPosition() == that.getPosition() && this.entryFormat == that.entryFormat && this.low == that.low && this.high == that.high) {
177205
return true;
178206
}
179207
}

compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFile.java

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
*/
2525
package org.graalvm.compiler.code;
2626

27+
import static org.graalvm.compiler.code.CompilationResult.JumpTable.EntryFormat.KEY2_OFFSET;
28+
import static org.graalvm.compiler.code.CompilationResult.JumpTable.EntryFormat.OFFSET;
29+
2730
import java.io.ByteArrayOutputStream;
2831
import java.io.OutputStream;
2932
import java.io.PrintStream;
@@ -37,8 +40,7 @@
3740
import org.graalvm.compiler.code.CompilationResult.CodeAnnotation;
3841
import org.graalvm.compiler.code.CompilationResult.CodeComment;
3942
import org.graalvm.compiler.code.CompilationResult.JumpTable;
40-
41-
import jdk.vm.ci.code.CodeUtil;
43+
import org.graalvm.compiler.code.CompilationResult.JumpTable.EntryFormat;
4244

4345
/**
4446
* A HexCodeFile is a textual format for representing a chunk of machine code along with extra
@@ -59,7 +61,9 @@
5961
*
6062
* OperandComment ::= "OperandComment" Position String
6163
*
62-
* JumpTable ::= "JumpTable" Position EntrySize Low High
64+
* EntryFormat ::= 4 | 8 | "OFFSET" | "KEY2_OFFSET"
65+
*
66+
* JumpTable ::= "JumpTable" Position EntryFormat Low High
6367
*
6468
* LookupTable ::= "LookupTable" Position NPairs KeySize OffsetSize
6569
*
@@ -95,13 +99,13 @@
9599
*/
96100
public class HexCodeFile {
97101

98-
public static final String NEW_LINE = CodeUtil.NEW_LINE;
102+
public static final String NEW_LINE = System.lineSeparator();
99103
public static final String SECTION_DELIM = " <||@";
100104
public static final String COLUMN_END = " <|@";
101105
public static final Pattern SECTION = Pattern.compile("(\\S+)\\s+(.*)", Pattern.DOTALL);
102106
public static final Pattern COMMENT = Pattern.compile("(\\d+)\\s+(.*)", Pattern.DOTALL);
103107
public static final Pattern OPERAND_COMMENT = COMMENT;
104-
public static final Pattern JUMP_TABLE = Pattern.compile("(\\d+)\\s+(\\d+)\\s+(-{0,1}\\d+)\\s+(-{0,1}\\d+)\\s*");
108+
public static final Pattern JUMP_TABLE = Pattern.compile("(\\d+)\\s+(\\S+)\\s+(-{0,1}\\d+)\\s+(-{0,1}\\d+)\\s*");
105109
public static final Pattern LOOKUP_TABLE = Pattern.compile("(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s*");
106110
public static final Pattern HEX_CODE = Pattern.compile("(\\p{XDigit}+)(?:\\s+(\\p{XDigit}*))?");
107111
public static final Pattern PLATFORM = Pattern.compile("(\\S+)\\s+(\\S+)", Pattern.DOTALL);
@@ -173,7 +177,10 @@ public void writeTo(OutputStream out) {
173177
ps.printf("HexCode %x %s %s%n", startAddress, HexCodeFile.hexCodeString(code), SECTION_DELIM);
174178

175179
for (JumpTable table : jumpTables) {
176-
ps.printf("JumpTable %d %d %d %d %s%n", table.getPosition(), table.entrySize, table.low, table.high, SECTION_DELIM);
180+
EntryFormat ef = table.entryFormat;
181+
// Backwards compatibility support for old versions of C1Visualizer
182+
String efString = ef == OFFSET || ef == KEY2_OFFSET ? String.valueOf(ef.size) : ef.name();
183+
ps.printf("JumpTable %d %s %d %d %s%n", table.getPosition(), efString, table.low, table.high, SECTION_DELIM);
177184
}
178185

179186
for (Map.Entry<Integer, List<String>> e : comments.entrySet()) {
@@ -433,13 +440,30 @@ void parseSection(int offset, String section) {
433440
m = HexCodeFile.JUMP_TABLE.matcher(body);
434441
check(m.matches(), bodyOffset, "JumpTable does not match pattern " + HexCodeFile.JUMP_TABLE);
435442
int pos = parseInt(bodyOffset + m.start(1), m.group(1));
436-
int entrySize = parseInt(bodyOffset + m.start(2), m.group(2));
443+
JumpTable.EntryFormat entryFormat = parseJumpTableEntryFormat(m, bodyOffset);
437444
int low = parseInt(bodyOffset + m.start(3), m.group(3));
438445
int high = parseInt(bodyOffset + m.start(4), m.group(4));
439-
hcf.jumpTables.add(new JumpTable(pos, low, high, entrySize));
446+
hcf.jumpTables.add(new JumpTable(pos, low, high, entryFormat));
440447
} else {
441448
error(offset, "Unknown section header: " + header);
442449
}
443450
}
451+
452+
private JumpTable.EntryFormat parseJumpTableEntryFormat(Matcher m, int bodyOffset) throws Error {
453+
String entryFormatName = m.group(2);
454+
JumpTable.EntryFormat entryFormat;
455+
if ("4".equals(entryFormatName)) {
456+
entryFormat = EntryFormat.OFFSET;
457+
} else if ("8".equals(entryFormatName)) {
458+
entryFormat = EntryFormat.KEY2_OFFSET;
459+
} else {
460+
try {
461+
entryFormat = EntryFormat.valueOf(entryFormatName);
462+
} catch (IllegalArgumentException e) {
463+
throw error(bodyOffset + m.start(2), "Not a valid " + EntryFormat.class.getSimpleName() + " value: " + entryFormatName);
464+
}
465+
}
466+
return entryFormat;
467+
}
444468
}
445469
}

compiler/src/org.graalvm.compiler.code/src/org/graalvm/compiler/code/HexCodeFileDisassemblerProvider.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import java.lang.invoke.MethodHandle;
2828
import java.lang.invoke.MethodHandles;
29+
import java.lang.reflect.Method;
2930
import java.util.Arrays;
3031

3132
import org.graalvm.compiler.options.OptionValues;
@@ -43,6 +44,7 @@
4344
import jdk.vm.ci.code.site.DataPatch;
4445
import jdk.vm.ci.code.site.ExceptionHandler;
4546
import jdk.vm.ci.code.site.Infopoint;
47+
import jdk.vm.ci.services.Services;
4648

4749
/**
4850
* {@link HexCodeFile} based implementation of {@link DisassemblerProvider}.
@@ -124,6 +126,11 @@ private static void addOperandComment(HexCodeFile hcf, int pos, String comment)
124126
hcf.addOperandComment(pos, comment);
125127
}
126128

129+
@Override
130+
public boolean isAvailable(OptionValues options) {
131+
return HexCodeFileDisTool.processMethod != null;
132+
}
133+
127134
/**
128135
* Interface to the tool for disassembling an {@link HexCodeFile#toEmbeddedString() embedded}
129136
* {@link HexCodeFile}.
@@ -135,10 +142,31 @@ static class HexCodeFileDisTool {
135142
MethodHandle toolMethod = null;
136143
try {
137144
Class<?> toolClass = Class.forName("com.oracle.max.hcfdis.HexCodeFileDis", true, ClassLoader.getSystemClassLoader());
138-
toolMethod = MethodHandles.lookup().unreflect(toolClass.getDeclaredMethod("processEmbeddedString", String.class));
145+
Method reflectMethod = toolClass.getDeclaredMethod("processEmbeddedString", String.class);
146+
reflectMethod.setAccessible(true);
147+
toolMethod = MethodHandles.lookup().unreflect(reflectMethod);
139148
} catch (Exception e) {
140149
// Tool not available on the class path
141150
}
151+
152+
// Try disassemble a zero-length code array to see if the disassembler
153+
// can really be used (e.g., the Capstone native support may be not available on the
154+
// current platform).
155+
if (toolMethod != null) {
156+
byte[] code = {};
157+
String arch = Services.getSavedProperties().get("os.arch");
158+
if (arch.equals("x86_64")) {
159+
arch = "amd64";
160+
}
161+
int wordWidth = arch.endsWith("64") ? 64 : Integer.parseInt(Services.getSavedProperties().getOrDefault("sun.arch.data.model", "64"));
162+
String hcf = new HexCodeFile(code, 0L, arch.toLowerCase(), wordWidth).toEmbeddedString();
163+
try {
164+
toolMethod.invokeExact(hcf);
165+
} catch (Throwable e) {
166+
toolMethod = null;
167+
}
168+
}
169+
142170
processMethod = toolMethod;
143171
}
144172

compiler/src/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ControlFlow.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
4141
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.ScratchRegister;
4242
import org.graalvm.compiler.code.CompilationResult.JumpTable;
43+
import org.graalvm.compiler.code.CompilationResult.JumpTable.EntryFormat;
4344
import org.graalvm.compiler.core.common.NumUtil;
4445
import org.graalvm.compiler.core.common.calc.Condition;
4546
import org.graalvm.compiler.debug.GraalError;
@@ -443,7 +444,7 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
443444
for (LabelRef target : targets) {
444445
masm.jmp(target.label());
445446
}
446-
JumpTable jt = new JumpTable(jumpTable.position(), lowKey, highKey, 4);
447+
JumpTable jt = new JumpTable(jumpTable.position(), lowKey, highKey, EntryFormat.OFFSET);
447448
crb.compilationResult.addAnnotation(jt);
448449
}
449450
}

compiler/src/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ControlFlow.java

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize;
4848
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
4949
import org.graalvm.compiler.code.CompilationResult.JumpTable;
50+
import org.graalvm.compiler.code.CompilationResult.JumpTable.EntryFormat;
5051
import org.graalvm.compiler.core.common.NumUtil;
5152
import org.graalvm.compiler.core.common.calc.Condition;
5253
import org.graalvm.compiler.debug.GraalError;
@@ -740,7 +741,7 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
740741
}
741742
}
742743

743-
JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, 4);
744+
JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, EntryFormat.OFFSET);
744745
crb.compilationResult.addAnnotation(jt);
745746
}
746747
}
@@ -800,13 +801,8 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
800801
masm.jmp(scratchReg);
801802

802803
// Inserting padding so that jump the table address is aligned
803-
int entrySize;
804-
if (defaultTarget != null) {
805-
entrySize = 8;
806-
} else {
807-
entrySize = 4;
808-
}
809-
masm.align(entrySize);
804+
EntryFormat entryFormat = defaultTarget == null ? EntryFormat.OFFSET : EntryFormat.KEY2_OFFSET;
805+
masm.align(entryFormat.size);
810806

811807
// Patch LEA instruction above now that we know the position of the jump table
812808
// this is ugly but there is no better way to do this given the assembler API
@@ -834,7 +830,7 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
834830
}
835831
}
836832

837-
JumpTable jt = new JumpTable(jumpTablePos, keys[0].asInt(), keys[keys.length - 1].asInt(), entrySize);
833+
JumpTable jt = new JumpTable(jumpTablePos, 0, keys.length - 1, entryFormat);
838834
crb.compilationResult.addAnnotation(jt);
839835
}
840836
}

compiler/src/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/hashing/IntHasher.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ private IntHasher(int cardinality, short factor, byte shift) {
4545
this.shift = shift;
4646
}
4747

48-
// 1 + the first 9999 prime numbers
48+
// 1 + the first 999 prime numbers
4949
private static final Short[] factors = new Short[1000];
5050

5151
static {

compiler/src/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -270,14 +270,17 @@ private static DisassemblerProvider selectDisassemblerProvider(OptionValues opti
270270
String arch = Services.getSavedProperties().get("os.arch");
271271
final boolean isAArch64 = arch.equals("aarch64");
272272
for (DisassemblerProvider d : GraalServices.load(DisassemblerProvider.class)) {
273-
String name = d.getName();
274-
if (isAArch64 && name.equals("objdump") && d.isAvailable(options)) {
275-
return d;
276-
} else if (name.equals("hcf")) {
277-
if (!isAArch64) {
273+
if (d.isAvailable(options)) {
274+
String name = d.getName();
275+
if (isAArch64 && name.equals("objdump")) {
276+
// Prefer objdump disassembler over others
278277
return d;
278+
} else if (name.equals("hcf")) {
279+
if (!isAArch64) {
280+
return d;
281+
}
282+
selected = d;
279283
}
280-
selected = d;
281284
}
282285
}
283286
if (selected == null) {

0 commit comments

Comments
 (0)