< prev index next >

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ControlFlow.java

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.

@@ -281,16 +281,14 @@
             masm.movslq(idxScratchReg, new AMD64Address(scratchReg, idxScratchReg, Scale.Times4, 0));
             masm.addq(scratchReg, idxScratchReg);
             masm.jmp(scratchReg);
 
             // Inserting padding so that jump table address is 4-byte aligned
-            if ((masm.position() & 0x3) != 0) {
-                masm.nop(4 - (masm.position() & 0x3));
-            }
+            masm.align(4);
 
             // Patch LEA instruction above now that we know the position of the jump table
-            // TODO this is ugly and should be done differently
+            // 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

@@ -312,10 +310,103 @@
             JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, 4);
             crb.compilationResult.addAnnotation(jt);
         }
     }
 
+    public static final class HashTableSwitchOp extends AMD64BlockEndOp {
+        public static final LIRInstructionClass<HashTableSwitchOp> TYPE = LIRInstructionClass.create(HashTableSwitchOp.class);
+        private final JavaConstant[] keys;
+        private final LabelRef defaultTarget;
+        private final LabelRef[] targets;
+        @Alive protected Value value;
+        @Alive protected Value hash;
+        @Temp({REG}) protected Value entryScratch;
+        @Temp({REG}) protected Value scratch;
+
+        public HashTableSwitchOp(final JavaConstant[] keys, final LabelRef defaultTarget, LabelRef[] targets, Value value, Value hash, Variable scratch, Variable entryScratch) {
+            super(TYPE);
+            this.keys = keys;
+            this.defaultTarget = defaultTarget;
+            this.targets = targets;
+            this.value = value;
+            this.hash = hash;
+            this.scratch = scratch;
+            this.entryScratch = entryScratch;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            Register valueReg = asRegister(value, AMD64Kind.DWORD);
+            Register indexReg = asRegister(hash, AMD64Kind.DWORD);
+            Register scratchReg = asRegister(scratch, AMD64Kind.QWORD);
+            Register entryScratchReg = asRegister(entryScratch, AMD64Kind.QWORD);
+
+            // Set scratch to address of jump table
+            masm.leaq(scratchReg, new AMD64Address(AMD64.rip, 0));
+            final int afterLea = masm.position();
+
+            // When the default target is set, the jump table contains entries with two DWORDS:
+            // the original key before hashing and the label jump address
+            if (defaultTarget != null) {
+
+                // Move the table entry (two DWORDs) into a QWORD
+                masm.movq(entryScratchReg, new AMD64Address(scratchReg, indexReg, Scale.Times8, 0));
+
+                // Jump to the default target if the first DWORD (original key) doesn't match the
+                // current key. Accounts for hash collisions with unknown keys
+                masm.cmpl(entryScratchReg, valueReg);
+                masm.jcc(ConditionFlag.NotEqual, defaultTarget.label());
+
+                // Shift to the second DWORD
+                masm.sarq(entryScratchReg, 32);
+            } else {
+
+                // The jump table has a single DWORD with the label address if there's no
+                // default target
+                masm.movslq(entryScratchReg, new AMD64Address(scratchReg, indexReg, Scale.Times4, 0));
+            }
+            masm.addq(scratchReg, entryScratchReg);
+            masm.jmp(scratchReg);
+
+            // Inserting padding so that jump the table address is aligned
+            if (defaultTarget != null) {
+                masm.align(8);
+            } else {
+                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
+            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.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, keys[0].asInt(), keys[keys.length - 1].asInt(), 4);
+            crb.compilationResult.addAnnotation(jt);
+        }
+    }
+
     @Opcode("SETcc")
     public static final class CondSetOp extends AMD64LIRInstruction {
         public static final LIRInstructionClass<CondSetOp> TYPE = LIRInstructionClass.create(CondSetOp.class);
         @Def({REG, HINT}) protected Value result;
         private final ConditionFlag condition;
< prev index next >