Skip to content

Commit 0ccc205

Browse files
committed
[GR-60152] Emit the jump tables in a slow path
PullRequest: graal/19452
2 parents 6dc9495 + 565adf0 commit 0ccc205

File tree

3 files changed

+110
-72
lines changed

3 files changed

+110
-72
lines changed

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4544,6 +4544,26 @@ public final void testl(Register dst, int imm32) {
45444544
}
45454545
}
45464546

4547+
/**
4548+
* Emit a UD2 instruction, this signals the processor to stop decoding instructions further in
4549+
* the fallthrough path (Intel Optimization Reference Manual Volume 1, section 3.4.1.5, Branch
4550+
* Type Selection, Assembly/Compiler coding rule 13).
4551+
* <p>
4552+
* This also helps when we want to emit data in the code section as it prevents mismatched
4553+
* instructions when decoding from different paths. E.g. consider this piece of hex code:
4554+
* <p>
4555+
* {@code 01 48 01 c8}
4556+
* <p>
4557+
* With {@code 01} being the data and {@code 48 01 c8} being {@code add rax, rcx}. However, if
4558+
* the decoder starts with {@code 01} it will see the next instruction being {@code 01 48 01}
4559+
* which is {@code add [rax + 1], ecx}. This mismatch invalidates the uop cache as the CPU
4560+
* cannot know which instruction sequence is the correct one.
4561+
*/
4562+
public void ud2() {
4563+
emitByte(0x0F);
4564+
emitByte(0x0B);
4565+
}
4566+
45474567
public final void vzeroupper() {
45484568
emitVEX(VEXPrefixConfig.L128, VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0, 0);
45494569
emitByte(0x77);

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ControlFlow.java

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -457,11 +457,15 @@ public static void emitJumpTable(CompilationResultBuilder crb, AArch64MacroAssem
457457
// jump to target
458458
masm.jmp(scratch);
459459

460-
masm.bind(jumpTable);
461-
// emit jump table entries
462-
targets.forEach(label -> masm.emitJumpTableOffset(jumpTable, label));
463-
JumpTable jt = new JumpTable(jumpTable.position(), lowKey, highKey, EntryFormat.OFFSET_ONLY);
464-
crb.compilationResult.addAnnotation(jt);
460+
crb.getLIR().addSlowPath(null, () -> {
461+
// Insert halt so that static analyzers do not continue decoding past this point
462+
masm.halt();
463+
masm.bind(jumpTable);
464+
// emit jump table entries
465+
targets.forEach(label -> masm.emitJumpTableOffset(jumpTable, label));
466+
JumpTable jt = new JumpTable(jumpTable.position(), lowKey, highKey, EntryFormat.OFFSET_ONLY);
467+
crb.compilationResult.addAnnotation(jt);
468+
});
465469
}
466470
}
467471

@@ -542,18 +546,22 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
542546
masm.jmp(jumpTableBase);
543547
}
544548

545-
// ensure jump table is aligned with the entry size
546-
masm.align(format.size);
547-
masm.bind(jumpTable);
548-
// emit jump table entries
549-
for (int i = 0; i < targets.length; i++) {
550-
if (format == EntryFormat.VALUE_AND_OFFSET) {
551-
masm.emitInt(keys[i].asInt());
549+
crb.getLIR().addSlowPath(this, () -> {
550+
// Insert halt so that static analyzers do not continue decoding past this point
551+
masm.halt();
552+
// ensure jump table is aligned with the entry size
553+
masm.align(format.size);
554+
masm.bind(jumpTable);
555+
// emit jump table entries
556+
for (int i = 0; i < targets.length; i++) {
557+
if (format == EntryFormat.VALUE_AND_OFFSET) {
558+
masm.emitInt(keys[i].asInt());
559+
}
560+
masm.emitJumpTableOffset(jumpTable, targets[i].label());
552561
}
553-
masm.emitJumpTableOffset(jumpTable, targets[i].label());
554-
}
555-
JumpTable jt = new JumpTable(jumpTable.position(), 0, keys.length - 1, format);
556-
crb.compilationResult.addAnnotation(jt);
562+
JumpTable jt = new JumpTable(jumpTable.position(), 0, keys.length - 1, format);
563+
crb.compilationResult.addAnnotation(jt);
564+
});
557565
}
558566
}
559567
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64ControlFlow.java

Lines changed: 65 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -711,32 +711,37 @@ public static void emitJumpTable(CompilationResultBuilder crb, AMD64MacroAssembl
711711
masm.addq(scratchReg, idxScratchReg);
712712
masm.jmp(scratchReg);
713713

714-
// Inserting padding so that jump table address is 4-byte aligned
715-
masm.align(4);
716-
717-
// Patch LEA instruction above now that we know the position of the jump table
718-
// this is ugly but there is no better way to do this given the assembler API
719-
final int jumpTablePos = masm.position();
720-
final int leaDisplacementPosition = afterLea - 4;
721-
masm.emitInt(jumpTablePos - afterLea, leaDisplacementPosition);
722-
723-
// Emit jump table entries
724-
targets.forEach(label -> {
725-
int offsetToJumpTableBase = masm.position() - jumpTablePos;
726-
if (label.isBound()) {
727-
int imm32 = label.position() - jumpTablePos;
728-
masm.emitInt(imm32);
729-
} else {
730-
label.addPatchAt(masm.position(), masm);
731-
732-
masm.emitByte(0); // pseudo-opcode for jump table entry
733-
masm.emitShort(offsetToJumpTableBase);
734-
masm.emitByte(0); // padding to make jump table entry 4 bytes wide
735-
}
714+
crb.getLIR().addSlowPath(null, () -> {
715+
// Insert halt so that static analyzers do not continue decoding past this point
716+
masm.hlt();
717+
// Insert ud2 so the CPU does not continue decoding past this point
718+
masm.ud2();
719+
// Inserting padding so that jump table address is 4-byte aligned
720+
masm.align(4);
721+
// Patch LEA instruction above now that we know the position of the jump table
722+
// this is ugly but there is no better way to do this given the assembler API
723+
int jumpTablePos = masm.position();
724+
int leaDisplacementPosition = afterLea - 4;
725+
masm.emitInt(jumpTablePos - afterLea, leaDisplacementPosition);
726+
727+
// Emit jump table entries
728+
targets.forEach(label -> {
729+
int offsetToJumpTableBase = masm.position() - jumpTablePos;
730+
if (label.isBound()) {
731+
int imm32 = label.position() - jumpTablePos;
732+
masm.emitInt(imm32);
733+
} else {
734+
label.addPatchAt(masm.position(), masm);
735+
736+
masm.emitByte(0); // pseudo-opcode for jump table entry
737+
masm.emitShort(offsetToJumpTableBase);
738+
masm.emitByte(0); // padding to make jump table entry 4 bytes wide
739+
}
740+
});
741+
742+
JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, EntryFormat.OFFSET_ONLY);
743+
crb.compilationResult.addAnnotation(jt);
736744
});
737-
738-
JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, EntryFormat.OFFSET_ONLY);
739-
crb.compilationResult.addAnnotation(jt);
740745
}
741746
}
742747

@@ -794,38 +799,43 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
794799
masm.addq(scratchReg, entryScratchReg);
795800
masm.jmp(scratchReg);
796801

797-
// Inserting padding so that jump the table address is aligned
798-
EntryFormat entryFormat = defaultTarget == null ? EntryFormat.OFFSET_ONLY : EntryFormat.VALUE_AND_OFFSET;
799-
masm.align(entryFormat.size);
800-
801-
// Patch LEA instruction above now that we know the position of the jump table
802-
// this is ugly but there is no better way to do this given the assembler API
803-
final int jumpTablePos = masm.position();
804-
final int leaDisplacementPosition = afterLea - 4;
805-
masm.emitInt(jumpTablePos - afterLea, leaDisplacementPosition);
806-
807-
// Emit jump table entries
808-
for (int i = 0; i < targets.length; i++) {
809-
810-
Label label = targets[i].label();
811-
812-
if (defaultTarget != null) {
813-
masm.emitInt(keys[i].asInt());
802+
crb.getLIR().addSlowPath(this, () -> {
803+
// Insert halt so that static analyzers do not continue decoding past this point
804+
masm.hlt();
805+
// Insert ud2 so the CPU does not continue decoding past this point
806+
masm.ud2();
807+
// Inserting padding so that jump the table address is aligned
808+
EntryFormat entryFormat = defaultTarget == null ? EntryFormat.OFFSET_ONLY : EntryFormat.VALUE_AND_OFFSET;
809+
masm.align(entryFormat.size);
810+
811+
// Patch LEA instruction above now that we know the position of the jump table
812+
// this is ugly but there is no better way to do this given the assembler API
813+
final int jumpTablePos = masm.position();
814+
final int leaDisplacementPosition = afterLea - 4;
815+
masm.emitInt(jumpTablePos - afterLea, leaDisplacementPosition);
816+
817+
// Emit jump table entries
818+
for (int i = 0; i < targets.length; i++) {
819+
Label label = targets[i].label();
820+
821+
if (defaultTarget != null) {
822+
masm.emitInt(keys[i].asInt());
823+
}
824+
if (label.isBound()) {
825+
int imm32 = label.position() - jumpTablePos;
826+
masm.emitInt(imm32);
827+
} else {
828+
int offsetToJumpTableBase = masm.position() - jumpTablePos;
829+
label.addPatchAt(masm.position(), masm);
830+
masm.emitByte(0); // pseudo-opcode for jump table entry
831+
masm.emitShort(offsetToJumpTableBase);
832+
masm.emitByte(0); // padding to make jump table entry 4 bytes wide
833+
}
814834
}
815-
if (label.isBound()) {
816-
int imm32 = label.position() - jumpTablePos;
817-
masm.emitInt(imm32);
818-
} else {
819-
int offsetToJumpTableBase = masm.position() - jumpTablePos;
820-
label.addPatchAt(masm.position(), masm);
821-
masm.emitByte(0); // pseudo-opcode for jump table entry
822-
masm.emitShort(offsetToJumpTableBase);
823-
masm.emitByte(0); // padding to make jump table entry 4 bytes wide
824-
}
825-
}
826835

827-
JumpTable jt = new JumpTable(jumpTablePos, 0, keys.length - 1, entryFormat);
828-
crb.compilationResult.addAnnotation(jt);
836+
JumpTable jt = new JumpTable(jumpTablePos, 0, keys.length - 1, entryFormat);
837+
crb.compilationResult.addAnnotation(jt);
838+
});
829839
}
830840
}
831841

0 commit comments

Comments
 (0)