1 /*
   2  * Copyright (c) 2015, 2018, 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 
  24 
  25 package org.graalvm.compiler.asm.amd64.test;
  26 
  27 import static jdk.vm.ci.code.ValueUtil.asRegister;
  28 import static org.junit.Assume.assumeTrue;
  29 
  30 import java.lang.reflect.Field;
  31 
  32 import jdk.vm.ci.amd64.AMD64;
  33 import jdk.vm.ci.code.CallingConvention;
  34 import jdk.vm.ci.code.Register;
  35 import jdk.vm.ci.code.RegisterConfig;
  36 import jdk.vm.ci.code.TargetDescription;
  37 import jdk.vm.ci.meta.JavaKind;
  38 
  39 import org.junit.Before;
  40 import org.junit.Test;
  41 
  42 import org.graalvm.compiler.asm.amd64.AMD64Address;
  43 import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
  44 import org.graalvm.compiler.asm.test.AssemblerTest;
  45 import org.graalvm.compiler.code.CompilationResult;
  46 
  47 public class IncrementDecrementMacroTest extends AssemblerTest {
  48 
  49     @Before
  50     public void checkAMD64() {
  51         assumeTrue("skipping AMD64 specific test", codeCache.getTarget().arch instanceof AMD64);
  52     }
  53 
  54     public static class LongField {
  55         public long x;
  56 
  57         LongField(long x) {
  58             this.x = x;
  59         }
  60     }
  61 
  62     private static class IncrementCodeGenTest implements CodeGenTest {
  63         final int value;
  64 
  65         IncrementCodeGenTest(int value) {
  66             this.value = value;
  67         }
  68 
  69         @Override
  70         public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
  71             AMD64MacroAssembler asm = new AMD64MacroAssembler(target);
  72             Register ret = registerConfig.getReturnRegister(JavaKind.Int);
  73             try {
  74                 Field f = LongField.class.getDeclaredField("x");
  75                 AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f));
  76                 asm.incrementq(arg, value);
  77                 asm.movq(ret, arg);
  78                 asm.ret(0);
  79                 return asm.close(true);
  80             } catch (Exception e) {
  81                 throw new RuntimeException("exception while trying to generate field access:", e);
  82             }
  83         }
  84     }
  85 
  86     private void assertIncrement(long initValue, int increment) {
  87         assertReturn("longFieldStubIncrement", new IncrementCodeGenTest(increment), initValue + increment, new LongField(initValue));
  88     }
  89 
  90     private void assertIncrements(int increment) {
  91         assertIncrement(0x4242_4242_4242_4242L, increment);
  92     }
  93 
  94     @SuppressWarnings("unused")
  95     public static long longFieldStubIncrement(LongField arg) {
  96         return 0;
  97     }
  98 
  99     private static class DecrementCodeGenTest implements CodeGenTest {
 100         final int value;
 101 
 102         DecrementCodeGenTest(int value) {
 103             this.value = value;
 104         }
 105 
 106         @Override
 107         public byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc) {
 108             AMD64MacroAssembler asm = new AMD64MacroAssembler(target);
 109             Register ret = registerConfig.getReturnRegister(JavaKind.Int);
 110             try {
 111                 Field f = LongField.class.getDeclaredField("x");
 112                 AMD64Address arg = new AMD64Address(asRegister(cc.getArgument(0)), (int) UNSAFE.objectFieldOffset(f));
 113                 asm.decrementq(arg, value);
 114                 asm.movq(ret, arg);
 115                 asm.ret(0);
 116                 return asm.close(true);
 117             } catch (Exception e) {
 118                 throw new RuntimeException("exception while trying to generate field access:", e);
 119             }
 120         }
 121     }
 122 
 123     private void assertDecrement(long initValue, int increment) {
 124         assertReturn("longFieldStubDecrement", new DecrementCodeGenTest(increment), initValue - increment, new LongField(initValue));
 125     }
 126 
 127     private void assertDecrements(int increment) {
 128         assertDecrement(0x4242_4242_4242_4242L, increment);
 129     }
 130 
 131     @SuppressWarnings("unused")
 132     public static long longFieldStubDecrement(LongField arg) {
 133         return 0;
 134     }
 135 
 136     @Test
 137     public void incrementMemTest0() {
 138         int increment = 0;
 139         assertIncrements(increment);
 140     }
 141 
 142     @Test
 143     public void incrementMemTest1() {
 144         int increment = 1;
 145         assertIncrements(increment);
 146     }
 147 
 148     @Test
 149     public void incrementMemTest2() {
 150         int increment = 2;
 151         assertIncrements(increment);
 152     }
 153 
 154     @Test
 155     public void incrementMemTest3() {
 156         int increment = Integer.MAX_VALUE;
 157         assertIncrements(increment);
 158     }
 159 
 160     @Test
 161     public void incrementMemTest4() {
 162         int increment = Integer.MIN_VALUE;
 163         assertIncrements(increment);
 164     }
 165 
 166     @Test
 167     public void incrementMemTest5() {
 168         int increment = -1;
 169         assertIncrements(increment);
 170     }
 171 
 172     @Test
 173     public void incrementMemTest6() {
 174         int increment = -2;
 175         assertIncrements(increment);
 176     }
 177 
 178     @Test
 179     public void incrementMemTest7() {
 180         int increment = -0x1000_0000;
 181         assertIncrements(increment);
 182     }
 183 
 184     @Test
 185     public void decrementMemTest0() {
 186         int decrement = 0;
 187         assertDecrements(decrement);
 188     }
 189 
 190     @Test
 191     public void decrementMemTest1() {
 192         int decrement = 1;
 193         assertDecrements(decrement);
 194     }
 195 
 196     @Test
 197     public void decrementMemTest2() {
 198         int decrement = 2;
 199         assertDecrements(decrement);
 200     }
 201 
 202     @Test
 203     public void decrementMemTest3() {
 204         int decrement = Integer.MAX_VALUE;
 205         assertDecrements(decrement);
 206     }
 207 
 208     @Test
 209     public void decrementMemTest4() {
 210         int decrement = Integer.MIN_VALUE;
 211         assertDecrements(decrement);
 212     }
 213 
 214     @Test
 215     public void decrementMemTest5() {
 216         int decrement = -1;
 217         assertDecrements(decrement);
 218     }
 219 
 220     @Test
 221     public void decrementMemTest6() {
 222         int decrement = -2;
 223         assertDecrements(decrement);
 224     }
 225 
 226     @Test
 227     public void decrementMemTest7() {
 228         int decrement = -0x1000_0000;
 229         assertDecrements(decrement);
 230     }
 231 
 232 }