diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java index d782f290c2e2..d2e6ce7a250a 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/amd64/AMD64Assembler.java @@ -4544,6 +4544,26 @@ public final void testl(Register dst, int imm32) { } } + /** + * Emit a UD2 instruction, this signals the processor to stop decoding instructions further in + * the fallthrough path (Intel Optimization Reference Manual Volume 1, section 3.4.1.5, Branch + * Type Selection, Assembly/Compiler coding rule 13). + *
+ * This also helps when we want to emit data in the code section as it prevents mismatched + * instructions when decoding from different paths. E.g. consider this piece of hex code: + *
+ * {@code 01 48 01 c8} + *
+ * With {@code 01} being the data and {@code 48 01 c8} being {@code add rax, rcx}. However, if + * the decoder starts with {@code 01} it will see the next instruction being {@code 01 48 01} + * which is {@code add [rax + 1], ecx}. This mismatch invalidates the uop cache as the CPU + * cannot know which instruction sequence is the correct one. + */ + public void ud2() { + emitByte(0x0F); + emitByte(0x0B); + } + public final void vzeroupper() { emitVEX(VEXPrefixConfig.L128, VEXPrefixConfig.P_, VEXPrefixConfig.M_0F, VEXPrefixConfig.W0, 0, 0); emitByte(0x77); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ControlFlow.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ControlFlow.java index 01388e8102ee..c4a68ac648a4 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ControlFlow.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/aarch64/AArch64ControlFlow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -457,11 +457,15 @@ public static void emitJumpTable(CompilationResultBuilder crb, AArch64MacroAssem // jump to target masm.jmp(scratch); - masm.bind(jumpTable); - // emit jump table entries - targets.forEach(label -> masm.emitJumpTableOffset(jumpTable, label)); - JumpTable jt = new JumpTable(jumpTable.position(), lowKey, highKey, EntryFormat.OFFSET_ONLY); - crb.compilationResult.addAnnotation(jt); + crb.getLIR().addSlowPath(null, () -> { + // Insert halt so that static analyzers do not continue decoding past this point + masm.halt(); + masm.bind(jumpTable); + // emit jump table entries + targets.forEach(label -> masm.emitJumpTableOffset(jumpTable, label)); + JumpTable jt = new JumpTable(jumpTable.position(), lowKey, highKey, EntryFormat.OFFSET_ONLY); + crb.compilationResult.addAnnotation(jt); + }); } } @@ -542,18 +546,22 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { masm.jmp(jumpTableBase); } - // ensure jump table is aligned with the entry size - masm.align(format.size); - masm.bind(jumpTable); - // emit jump table entries - for (int i = 0; i < targets.length; i++) { - if (format == EntryFormat.VALUE_AND_OFFSET) { - masm.emitInt(keys[i].asInt()); + crb.getLIR().addSlowPath(this, () -> { + // Insert halt so that static analyzers do not continue decoding past this point + masm.halt(); + // ensure jump table is aligned with the entry size + masm.align(format.size); + masm.bind(jumpTable); + // emit jump table entries + for (int i = 0; i < targets.length; i++) { + if (format == EntryFormat.VALUE_AND_OFFSET) { + masm.emitInt(keys[i].asInt()); + } + masm.emitJumpTableOffset(jumpTable, targets[i].label()); } - masm.emitJumpTableOffset(jumpTable, targets[i].label()); - } - JumpTable jt = new JumpTable(jumpTable.position(), 0, keys.length - 1, format); - crb.compilationResult.addAnnotation(jt); + JumpTable jt = new JumpTable(jumpTable.position(), 0, keys.length - 1, format); + crb.compilationResult.addAnnotation(jt); + }); } } } diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64ControlFlow.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64ControlFlow.java index 47f39bed188e..219331eacf88 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64ControlFlow.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/amd64/AMD64ControlFlow.java @@ -711,32 +711,37 @@ public static void emitJumpTable(CompilationResultBuilder crb, AMD64MacroAssembl masm.addq(scratchReg, idxScratchReg); masm.jmp(scratchReg); - // Inserting padding so that jump table address is 4-byte aligned - masm.align(4); - - // Patch LEA instruction above now that we know the position of the jump table - // this is ugly but there is no better way to do this given the assembler API - final int jumpTablePos = masm.position(); - final int leaDisplacementPosition = afterLea - 4; - masm.emitInt(jumpTablePos - afterLea, leaDisplacementPosition); - - // Emit jump table entries - targets.forEach(label -> { - int offsetToJumpTableBase = masm.position() - jumpTablePos; - if (label.isBound()) { - int imm32 = label.position() - jumpTablePos; - masm.emitInt(imm32); - } else { - label.addPatchAt(masm.position(), masm); - - masm.emitByte(0); // pseudo-opcode for jump table entry - masm.emitShort(offsetToJumpTableBase); - masm.emitByte(0); // padding to make jump table entry 4 bytes wide - } + crb.getLIR().addSlowPath(null, () -> { + // Insert halt so that static analyzers do not continue decoding past this point + masm.hlt(); + // Insert ud2 so the CPU does not continue decoding past this point + masm.ud2(); + // Inserting padding so that jump table address is 4-byte aligned + masm.align(4); + // Patch LEA instruction above now that we know the position of the jump table + // this is ugly but there is no better way to do this given the assembler API + int jumpTablePos = masm.position(); + int leaDisplacementPosition = afterLea - 4; + masm.emitInt(jumpTablePos - afterLea, leaDisplacementPosition); + + // Emit jump table entries + targets.forEach(label -> { + int offsetToJumpTableBase = masm.position() - jumpTablePos; + if (label.isBound()) { + int imm32 = label.position() - jumpTablePos; + masm.emitInt(imm32); + } else { + label.addPatchAt(masm.position(), masm); + + masm.emitByte(0); // pseudo-opcode for jump table entry + masm.emitShort(offsetToJumpTableBase); + masm.emitByte(0); // padding to make jump table entry 4 bytes wide + } + }); + + JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, EntryFormat.OFFSET_ONLY); + crb.compilationResult.addAnnotation(jt); }); - - JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, EntryFormat.OFFSET_ONLY); - crb.compilationResult.addAnnotation(jt); } } @@ -794,38 +799,43 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { masm.addq(scratchReg, entryScratchReg); masm.jmp(scratchReg); - // Inserting padding so that jump the table address is aligned - EntryFormat entryFormat = defaultTarget == null ? EntryFormat.OFFSET_ONLY : EntryFormat.VALUE_AND_OFFSET; - masm.align(entryFormat.size); - - // Patch LEA instruction above now that we know the position of the jump table - // this is ugly but there is no better way to do this given the assembler API - final int jumpTablePos = masm.position(); - final int leaDisplacementPosition = afterLea - 4; - masm.emitInt(jumpTablePos - afterLea, leaDisplacementPosition); - - // Emit jump table entries - for (int i = 0; i < targets.length; i++) { - - Label label = targets[i].label(); - - if (defaultTarget != null) { - masm.emitInt(keys[i].asInt()); + crb.getLIR().addSlowPath(this, () -> { + // Insert halt so that static analyzers do not continue decoding past this point + masm.hlt(); + // Insert ud2 so the CPU does not continue decoding past this point + masm.ud2(); + // Inserting padding so that jump the table address is aligned + EntryFormat entryFormat = defaultTarget == null ? EntryFormat.OFFSET_ONLY : EntryFormat.VALUE_AND_OFFSET; + masm.align(entryFormat.size); + + // Patch LEA instruction above now that we know the position of the jump table + // this is ugly but there is no better way to do this given the assembler API + final int jumpTablePos = masm.position(); + final int leaDisplacementPosition = afterLea - 4; + masm.emitInt(jumpTablePos - afterLea, leaDisplacementPosition); + + // Emit jump table entries + for (int i = 0; i < targets.length; i++) { + Label label = targets[i].label(); + + if (defaultTarget != null) { + masm.emitInt(keys[i].asInt()); + } + if (label.isBound()) { + int imm32 = label.position() - jumpTablePos; + masm.emitInt(imm32); + } else { + int offsetToJumpTableBase = masm.position() - jumpTablePos; + label.addPatchAt(masm.position(), masm); + masm.emitByte(0); // pseudo-opcode for jump table entry + masm.emitShort(offsetToJumpTableBase); + masm.emitByte(0); // padding to make jump table entry 4 bytes wide + } } - if (label.isBound()) { - int imm32 = label.position() - jumpTablePos; - masm.emitInt(imm32); - } else { - int offsetToJumpTableBase = masm.position() - jumpTablePos; - label.addPatchAt(masm.position(), masm); - masm.emitByte(0); // pseudo-opcode for jump table entry - masm.emitShort(offsetToJumpTableBase); - masm.emitByte(0); // padding to make jump table entry 4 bytes wide - } - } - JumpTable jt = new JumpTable(jumpTablePos, 0, keys.length - 1, entryFormat); - crb.compilationResult.addAnnotation(jt); + JumpTable jt = new JumpTable(jumpTablePos, 0, keys.length - 1, entryFormat); + crb.compilationResult.addAnnotation(jt); + }); } }