001/*
002 * Copyright (c) 2015, 2015, 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 */
023package com.oracle.graal.replacements.test;
024
025import java.util.*;
026
027import jdk.internal.jvmci.meta.*;
028
029import org.junit.*;
030
031import com.oracle.graal.api.directives.*;
032import com.oracle.graal.compiler.test.*;
033import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
034import com.oracle.graal.graphbuilderconf.*;
035import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
036import com.oracle.graal.nodes.*;
037import com.oracle.graal.replacements.*;
038import com.oracle.graal.word.*;
039import com.oracle.graal.word.nodes.*;
040
041/**
042 * Tests for derived oops in reference maps.
043 */
044public class DerivedOopTest extends GraalCompilerTest implements Snippets {
045
046    private static class Pointers {
047        public long basePointer;
048        public long internalPointer;
049
050        public long delta() {
051            return internalPointer - basePointer;
052        }
053
054        @Override
055        public boolean equals(Object obj) {
056            if (!(obj instanceof Pointers)) {
057                return false;
058            }
059
060            Pointers other = (Pointers) obj;
061            return this.delta() == other.delta();
062        }
063
064        @Override
065        public int hashCode() {
066            return (int) delta();
067        }
068    }
069
070    private static class Result {
071        public Pointers beforeGC;
072        public Pointers afterGC;
073
074        public Result() {
075            beforeGC = new Pointers();
076            afterGC = new Pointers();
077        }
078
079        @Override
080        public int hashCode() {
081            final int prime = 31;
082            int result = 1;
083            result = prime * result + ((afterGC == null) ? 0 : afterGC.hashCode());
084            result = prime * result + ((beforeGC == null) ? 0 : beforeGC.hashCode());
085            return result;
086        }
087
088        @Override
089        public boolean equals(Object obj) {
090            if (!(obj instanceof Result)) {
091                return false;
092            }
093            Result other = (Result) obj;
094            return Objects.equals(this.beforeGC, other.beforeGC) && Objects.equals(this.afterGC, other.afterGC);
095        }
096    }
097
098    @Test
099    public void testFieldOffset() {
100        // Run a couple times to encourage objects to move
101        for (int i = 0; i < 4; i++) {
102            Result r = new Result();
103            test("fieldOffsetSnippet", r, 16L);
104
105            Assert.assertEquals(r.beforeGC.delta(), r.afterGC.delta());
106        }
107    }
108
109    static long getRawPointer(Object obj) {
110        // fake implementation for interpreter
111        return obj.hashCode();
112    }
113
114    static long getRawPointerIntrinsic(Object obj) {
115        return Word.fromObject(obj).rawValue();
116    }
117
118    public static Result fieldOffsetSnippet(Result obj, long offset) {
119        long internalPointer = getRawPointer(obj) + offset;
120
121        // make sure the internal pointer is computed before the safepoint
122        GraalDirectives.blackhole(internalPointer);
123
124        obj.beforeGC.basePointer = getRawPointer(obj);
125        obj.beforeGC.internalPointer = internalPointer;
126
127        System.gc();
128
129        obj.afterGC.basePointer = getRawPointer(obj);
130        obj.afterGC.internalPointer = internalPointer;
131
132        return obj;
133    }
134
135    @Override
136    protected Plugins getDefaultGraphBuilderPlugins() {
137        Plugins plugins = super.getDefaultGraphBuilderPlugins();
138        Registration r = new Registration(plugins.getInvocationPlugins(), DerivedOopTest.class);
139
140        ResolvedJavaMethod intrinsic = getResolvedJavaMethod("getRawPointerIntrinsic");
141        r.register1("getRawPointer", Object.class, new InvocationPlugin() {
142            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
143                b.intrinsify(targetMethod, intrinsic, new ValueNode[]{arg});
144                return true;
145            }
146        });
147
148        return plugins;
149    }
150
151    @Override
152    protected boolean checkHighTierGraph(StructuredGraph graph) {
153        assert graph.getNodes().filter(WordCastNode.class).count() > 0 : "DerivedOopTest.toLong should be intrinsified";
154        return super.checkHighTierGraph(graph);
155    }
156}