001/*
002 * Copyright (c) 2011, 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 jdk.internal.jvmci.hotspot;
024
025import static jdk.internal.jvmci.common.UnsafeAccess.*;
026import jdk.internal.jvmci.code.*;
027import jdk.internal.jvmci.common.*;
028import jdk.internal.jvmci.hotspot.HotSpotVMConfig.*;
029import jdk.internal.jvmci.meta.*;
030
031/**
032 * HotSpot implementation of {@link MemoryAccessProvider}.
033 */
034public class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider, HotSpotProxified {
035
036    protected final HotSpotJVMCIRuntimeProvider runtime;
037
038    public HotSpotMemoryAccessProviderImpl(HotSpotJVMCIRuntimeProvider runtime) {
039        this.runtime = runtime;
040    }
041
042    private static Object asObject(Constant base) {
043        if (base instanceof HotSpotObjectConstantImpl) {
044            return ((HotSpotObjectConstantImpl) base).object();
045        } else {
046            return null;
047        }
048    }
049
050    private boolean isValidObjectFieldDisplacement(Constant base, long displacement) {
051        if (base instanceof HotSpotMetaspaceConstant) {
052            Object metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base);
053            if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) {
054                if (displacement == runtime.getConfig().classMirrorOffset) {
055                    // Klass::_java_mirror is valid for all Klass* values
056                    return true;
057                } else if (displacement == runtime.getConfig().arrayKlassComponentMirrorOffset) {
058                    // ArrayKlass::_component_mirror is only valid for all ArrayKlass* values
059                    return ((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror().isArray();
060                }
061            } else {
062                throw new JVMCIError("%s", metaspaceObject);
063            }
064        }
065        return false;
066    }
067
068    private static long asRawPointer(Constant base) {
069        if (base instanceof HotSpotMetaspaceConstant) {
070            return ((HotSpotMetaspaceConstant) base).rawValue();
071        } else if (base instanceof PrimitiveConstant) {
072            PrimitiveConstant prim = (PrimitiveConstant) base;
073            if (prim.getKind().isNumericInteger()) {
074                return prim.asLong();
075            }
076        }
077        throw new JVMCIError("%s", base);
078    }
079
080    private static long readRawValue(Constant baseConstant, long displacement, int bits) {
081        Object base = asObject(baseConstant);
082        if (base != null) {
083            switch (bits) {
084                case 8:
085                    return unsafe.getByte(base, displacement);
086                case 16:
087                    return unsafe.getShort(base, displacement);
088                case 32:
089                    return unsafe.getInt(base, displacement);
090                case 64:
091                    return unsafe.getLong(base, displacement);
092                default:
093                    throw new JVMCIError("%d", bits);
094            }
095        } else {
096            long pointer = asRawPointer(baseConstant);
097            switch (bits) {
098                case 8:
099                    return unsafe.getByte(pointer + displacement);
100                case 16:
101                    return unsafe.getShort(pointer + displacement);
102                case 32:
103                    return unsafe.getInt(pointer + displacement);
104                case 64:
105                    return unsafe.getLong(pointer + displacement);
106                default:
107                    throw new JVMCIError("%d", bits);
108            }
109        }
110    }
111
112    private boolean verifyReadRawObject(Object expected, Constant base, long displacement, boolean compressed) {
113        if (compressed == runtime.getConfig().useCompressedOops) {
114            Object obj = asObject(base);
115            if (obj != null) {
116                assert expected == unsafe.getObject(obj, displacement) : "readUnsafeOop doesn't agree with unsafe.getObject";
117            }
118        }
119        if (base instanceof HotSpotMetaspaceConstant) {
120            Object metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base);
121            if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) {
122                if (displacement == runtime.getConfig().classMirrorOffset) {
123                    assert expected == ((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror();
124                } else if (displacement == runtime.getConfig().arrayKlassComponentMirrorOffset) {
125                    assert expected == ((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror().getComponentType();
126                }
127            }
128        }
129        return true;
130    }
131
132    private Object readRawObject(Constant baseConstant, long initialDisplacement, boolean compressed) {
133        long displacement = initialDisplacement;
134
135        Object ret;
136        Object base = asObject(baseConstant);
137        if (base == null) {
138            assert !compressed;
139            displacement += asRawPointer(baseConstant);
140            ret = runtime.getCompilerToVM().readUncompressedOop(displacement);
141        } else {
142            assert runtime.getConfig().useCompressedOops == compressed;
143            ret = unsafe.getObject(base, displacement);
144        }
145        assert verifyReadRawObject(ret, baseConstant, initialDisplacement, compressed);
146        return ret;
147    }
148
149    @Override
150    public JavaConstant readUnsafeConstant(Kind kind, JavaConstant baseConstant, long displacement) {
151        if (kind == Kind.Object) {
152            Object o = readRawObject(baseConstant, displacement, runtime.getConfig().useCompressedOops);
153            return HotSpotObjectConstantImpl.forObject(o);
154        } else {
155            return readPrimitiveConstant(kind, baseConstant, displacement, kind.getByteCount() * 8);
156        }
157    }
158
159    @Override
160    public JavaConstant readPrimitiveConstant(Kind kind, Constant baseConstant, long initialDisplacement, int bits) {
161        try {
162            long rawValue = readRawValue(baseConstant, initialDisplacement, bits);
163            switch (kind) {
164                case Boolean:
165                    return JavaConstant.forBoolean(rawValue != 0);
166                case Byte:
167                    return JavaConstant.forByte((byte) rawValue);
168                case Char:
169                    return JavaConstant.forChar((char) rawValue);
170                case Short:
171                    return JavaConstant.forShort((short) rawValue);
172                case Int:
173                    return JavaConstant.forInt((int) rawValue);
174                case Long:
175                    return JavaConstant.forLong(rawValue);
176                case Float:
177                    return JavaConstant.forFloat(Float.intBitsToFloat((int) rawValue));
178                case Double:
179                    return JavaConstant.forDouble(Double.longBitsToDouble(rawValue));
180                default:
181                    throw new JVMCIError("Unsupported kind: %s", kind);
182            }
183        } catch (NullPointerException e) {
184            return null;
185        }
186    }
187
188    @Override
189    public JavaConstant readObjectConstant(Constant base, long displacement) {
190        if (!isValidObjectFieldDisplacement(base, displacement)) {
191            return null;
192        }
193        return HotSpotObjectConstantImpl.forObject(readRawObject(base, displacement, false));
194    }
195
196    @Override
197    public JavaConstant readNarrowOopConstant(Constant base, long displacement, CompressEncoding encoding) {
198        assert encoding.equals(runtime.getConfig().getOopEncoding()) : "unexpected oop encoding: " + encoding + " != " + runtime.getConfig().getOopEncoding();
199        return HotSpotObjectConstantImpl.forObject(readRawObject(base, displacement, true), true);
200    }
201
202    @Override
203    public Constant readKlassPointerConstant(Constant base, long displacement) {
204        TargetDescription target = runtime.getHostJVMCIBackend().getCodeCache().getTarget();
205        long klass = readRawValue(base, displacement, target.wordSize * 8);
206        if (klass == 0) {
207            return JavaConstant.NULL_POINTER;
208        }
209        HotSpotResolvedObjectType metaKlass = HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(klass);
210        return HotSpotMetaspaceConstantImpl.forMetaspaceObject(target.wordKind, klass, metaKlass, false);
211    }
212
213    @Override
214    public Constant readNarrowKlassPointerConstant(Constant base, long displacement, CompressEncoding encoding) {
215        int compressed = (int) readRawValue(base, displacement, 32);
216        long klass = encoding.uncompress(compressed);
217        if (klass == 0) {
218            return HotSpotCompressedNullConstant.COMPRESSED_NULL;
219        }
220        HotSpotResolvedObjectType metaKlass = HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(klass);
221        return HotSpotMetaspaceConstantImpl.forMetaspaceObject(Kind.Int, compressed, metaKlass, true);
222    }
223
224    @Override
225    public Constant readMethodPointerConstant(Constant base, long displacement) {
226        TargetDescription target = runtime.getHostJVMCIBackend().getCodeCache().getTarget();
227        long method = readRawValue(base, displacement, target.wordSize * 8);
228        HotSpotResolvedJavaMethod metaMethod = HotSpotResolvedJavaMethodImpl.fromMetaspace(method);
229        return HotSpotMetaspaceConstantImpl.forMetaspaceObject(target.wordKind, method, metaMethod, false);
230    }
231}