001/*
002 * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023
024package com.oracle.graal.hotspot.amd64.test;
025
026import jdk.internal.jvmci.amd64.*;
027import jdk.internal.jvmci.hotspot.*;
028import jdk.internal.jvmci.meta.*;
029import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
030import static jdk.internal.jvmci.code.ValueUtil.*;
031
032import org.junit.*;
033
034import com.oracle.graal.api.replacements.*;
035import com.oracle.graal.asm.amd64.*;
036import com.oracle.graal.graph.*;
037import com.oracle.graal.hotspot.*;
038import com.oracle.graal.hotspot.nodes.*;
039import com.oracle.graal.hotspot.nodes.CompressionNode.CompressionOp;
040import com.oracle.graal.hotspot.nodes.type.*;
041import com.oracle.graal.hotspot.test.*;
042import com.oracle.graal.lir.*;
043import com.oracle.graal.lir.asm.*;
044import com.oracle.graal.lir.gen.*;
045import com.oracle.graal.nodeinfo.*;
046import com.oracle.graal.nodes.*;
047import com.oracle.graal.nodes.spi.*;
048
049public class DataPatchInConstantsTest extends HotSpotGraalCompilerTest {
050
051    @Before
052    public void checkAMD64() {
053        Assume.assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
054    }
055
056    private static final Object object = new Object() {
057
058        @Override
059        public String toString() {
060            return "testObject";
061        }
062    };
063
064    private static Object loadThroughPatch(Object obj) {
065        return obj;
066    }
067
068    public static Object oopSnippet() {
069        Object patch = loadThroughPatch(object);
070        if (object != patch) {
071            return "invalid patch";
072        }
073        System.gc();
074        patch = loadThroughPatch(object);
075        if (object != patch) {
076            return "failed after gc";
077        }
078        return patch;
079    }
080
081    @Test
082    public void oopTest() {
083        test("oopSnippet");
084    }
085
086    private static Object loadThroughCompressedPatch(Object obj) {
087        return obj;
088    }
089
090    public static Object narrowOopSnippet() {
091        Object patch = loadThroughCompressedPatch(object);
092        if (object != patch) {
093            return "invalid patch";
094        }
095        System.gc();
096        patch = loadThroughCompressedPatch(object);
097        if (object != patch) {
098            return "failed after gc";
099        }
100        return patch;
101    }
102
103    @Test
104    public void narrowOopTest() {
105        Assume.assumeTrue("skipping narrow oop data patch test", config.useCompressedOops);
106        test("narrowOopSnippet");
107    }
108
109    public static Object compareSnippet() {
110        Object uncompressed = loadThroughPatch(object);
111        Object compressed = loadThroughCompressedPatch(object);
112        if (object != uncompressed) {
113            return "uncompressed failed";
114        }
115        if (object != compressed) {
116            return "compressed failed";
117        }
118        if (uncompressed != compressed) {
119            return "uncompressed != compressed";
120        }
121        return object;
122    }
123
124    @Test
125    public void compareTest() {
126        Assume.assumeTrue("skipping narrow oop data patch test", config.useCompressedOops);
127        test("compareSnippet");
128    }
129
130    private static final HotSpotVMConfig config = HotSpotGraalRuntime.runtime().getConfig();
131    private static boolean initReplacements = false;
132
133    @Before
134    public void initReplacements() {
135        if (!initReplacements) {
136            getReplacements().registerSubstitutions(DataPatchInConstantsTest.class, DataPatchInConstantsTestSubstitutions.class);
137            initReplacements = true;
138        }
139    }
140
141    @ClassSubstitution(DataPatchInConstantsTest.class)
142    private static class DataPatchInConstantsTestSubstitutions {
143
144        @MethodSubstitution
145        public static Object loadThroughPatch(Object obj) {
146            return LoadThroughPatchNode.load(obj);
147        }
148
149        @MethodSubstitution
150        public static Object loadThroughCompressedPatch(Object obj) {
151            Object compressed = CompressionNode.compression(CompressionOp.Compress, obj, config.getOopEncoding());
152            Object patch = LoadThroughPatchNode.load(compressed);
153            return CompressionNode.compression(CompressionOp.Uncompress, patch, config.getOopEncoding());
154        }
155    }
156
157    @NodeInfo
158    private static final class LoadThroughPatchNode extends FixedWithNextNode implements LIRLowerable {
159        public static final NodeClass<LoadThroughPatchNode> TYPE = NodeClass.create(LoadThroughPatchNode.class);
160
161        @Input protected ValueNode input;
162
163        public LoadThroughPatchNode(ValueNode input) {
164            super(TYPE, input.stamp());
165            this.input = input;
166        }
167
168        public void generate(NodeLIRBuilderTool generator) {
169            assert input.isConstant();
170
171            LIRGeneratorTool gen = generator.getLIRGeneratorTool();
172            Variable ret = gen.newVariable(gen.getLIRKind(stamp()));
173
174            gen.append(new LoadThroughPatchOp(input.asConstant(), stamp() instanceof NarrowOopStamp, ret));
175            generator.setResult(this, ret);
176        }
177
178        @NodeIntrinsic
179        public static native Object load(Object obj);
180    }
181
182    private static final class LoadThroughPatchOp extends LIRInstruction {
183        public static final LIRInstructionClass<LoadThroughPatchOp> TYPE = LIRInstructionClass.create(LoadThroughPatchOp.class);
184
185        final Constant c;
186        final boolean compressed;
187        @Def({REG}) AllocatableValue result;
188
189        LoadThroughPatchOp(Constant c, boolean compressed, AllocatableValue result) {
190            super(TYPE);
191            this.c = c;
192            this.compressed = compressed;
193            this.result = result;
194        }
195
196        @Override
197        public void emitCode(CompilationResultBuilder crb) {
198            AMD64Address address = (AMD64Address) crb.recordDataReferenceInCode(c, compressed ? 4 : 8);
199            AMD64MacroAssembler asm = (AMD64MacroAssembler) crb.asm;
200            if (compressed) {
201                asm.movl(asRegister(result), address);
202            } else {
203                asm.movq(asRegister(result), address);
204            }
205        }
206    }
207}