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 static jdk.internal.jvmci.hotspot.HotSpotResolvedJavaType.*;
027import static jdk.internal.jvmci.hotspot.HotSpotResolvedObjectTypeImpl.*;
028
029import java.lang.reflect.*;
030
031import jdk.internal.jvmci.code.*;
032import jdk.internal.jvmci.common.*;
033import jdk.internal.jvmci.meta.*;
034
035// JaCoCo Exclude
036
037/**
038 * HotSpot implementation of {@link MetaAccessProvider}.
039 */
040public class HotSpotMetaAccessProvider implements MetaAccessProvider, HotSpotProxified {
041
042    protected final HotSpotJVMCIRuntimeProvider runtime;
043
044    public HotSpotMetaAccessProvider(HotSpotJVMCIRuntimeProvider runtime) {
045        this.runtime = runtime;
046    }
047
048    public ResolvedJavaType lookupJavaType(Class<?> clazz) {
049        if (clazz == null) {
050            throw new IllegalArgumentException("Class parameter was null");
051        }
052        return runtime.fromClass(clazz);
053    }
054
055    public HotSpotResolvedObjectType lookupJavaType(JavaConstant constant) {
056        if (constant.isNull() || !(constant instanceof HotSpotObjectConstant)) {
057            return null;
058        }
059        return ((HotSpotObjectConstant) constant).getType();
060    }
061
062    public Signature parseMethodDescriptor(String signature) {
063        return new HotSpotSignature(runtime, signature);
064    }
065
066    /**
067     * {@link Field} object of {@link Method#slot}.
068     */
069    @SuppressWarnings("javadoc") private Field reflectionMethodSlot = getReflectionSlotField(Method.class);
070
071    /**
072     * {@link Field} object of {@link Constructor#slot}.
073     */
074    @SuppressWarnings("javadoc") private Field reflectionConstructorSlot = getReflectionSlotField(Constructor.class);
075
076    private static Field getReflectionSlotField(Class<?> reflectionClass) {
077        try {
078            Field field = reflectionClass.getDeclaredField("slot");
079            field.setAccessible(true);
080            return field;
081        } catch (NoSuchFieldException | SecurityException e) {
082            throw new JVMCIError(e);
083        }
084    }
085
086    public ResolvedJavaMethod lookupJavaMethod(Executable reflectionMethod) {
087        try {
088            Class<?> holder = reflectionMethod.getDeclaringClass();
089            Field slotField = reflectionMethod instanceof Constructor ? reflectionConstructorSlot : reflectionMethodSlot;
090            final int slot = slotField.getInt(reflectionMethod);
091            final long metaspaceMethod = runtime.getCompilerToVM().getMetaspaceMethod(holder, slot);
092            return HotSpotResolvedJavaMethodImpl.fromMetaspace(metaspaceMethod);
093        } catch (IllegalArgumentException | IllegalAccessException e) {
094            throw new JVMCIError(e);
095        }
096    }
097
098    public ResolvedJavaField lookupJavaField(Field reflectionField) {
099        String name = reflectionField.getName();
100        Class<?> fieldHolder = reflectionField.getDeclaringClass();
101        Class<?> fieldType = reflectionField.getType();
102        // java.lang.reflect.Field's modifiers should be enough here since VM internal modifier bits
103        // are not used (yet).
104        final int modifiers = reflectionField.getModifiers();
105        final long offset = Modifier.isStatic(modifiers) ? unsafe.staticFieldOffset(reflectionField) : unsafe.objectFieldOffset(reflectionField);
106
107        HotSpotResolvedObjectType holder = fromObjectClass(fieldHolder);
108        JavaType type = fromClass(fieldType);
109
110        if (offset != -1) {
111            HotSpotResolvedObjectType resolved = holder;
112            return resolved.createField(name, type, offset, modifiers);
113        } else {
114            throw new JVMCIError("unresolved field %s", reflectionField);
115        }
116    }
117
118    private static int intMaskRight(int n) {
119        assert n <= 32;
120        return n == 32 ? -1 : (1 << n) - 1;
121    }
122
123    @Override
124    public JavaConstant encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason, int debugId) {
125        HotSpotVMConfig config = runtime.getConfig();
126        int actionValue = convertDeoptAction(action);
127        int reasonValue = convertDeoptReason(reason);
128        int debugValue = debugId & intMaskRight(config.deoptimizationDebugIdBits);
129        JavaConstant c = JavaConstant.forInt(~((debugValue << config.deoptimizationDebugIdShift) | (reasonValue << config.deoptimizationReasonShift) | (actionValue << config.deoptimizationActionShift)));
130        assert c.asInt() < 0;
131        return c;
132    }
133
134    public DeoptimizationReason decodeDeoptReason(JavaConstant constant) {
135        HotSpotVMConfig config = runtime.getConfig();
136        int reasonValue = ((~constant.asInt()) >> config.deoptimizationReasonShift) & intMaskRight(config.deoptimizationReasonBits);
137        DeoptimizationReason reason = convertDeoptReason(reasonValue);
138        return reason;
139    }
140
141    public DeoptimizationAction decodeDeoptAction(JavaConstant constant) {
142        HotSpotVMConfig config = runtime.getConfig();
143        int actionValue = ((~constant.asInt()) >> config.deoptimizationActionShift) & intMaskRight(config.deoptimizationActionBits);
144        DeoptimizationAction action = convertDeoptAction(actionValue);
145        return action;
146    }
147
148    public int decodeDebugId(JavaConstant constant) {
149        HotSpotVMConfig config = runtime.getConfig();
150        return ((~constant.asInt()) >> config.deoptimizationDebugIdShift) & intMaskRight(config.deoptimizationDebugIdBits);
151    }
152
153    public int convertDeoptAction(DeoptimizationAction action) {
154        HotSpotVMConfig config = runtime.getConfig();
155        switch (action) {
156            case None:
157                return config.deoptActionNone;
158            case RecompileIfTooManyDeopts:
159                return config.deoptActionMaybeRecompile;
160            case InvalidateReprofile:
161                return config.deoptActionReinterpret;
162            case InvalidateRecompile:
163                return config.deoptActionMakeNotEntrant;
164            case InvalidateStopCompiling:
165                return config.deoptActionMakeNotCompilable;
166            default:
167                throw new JVMCIError("%s", action);
168        }
169    }
170
171    public DeoptimizationAction convertDeoptAction(int action) {
172        HotSpotVMConfig config = runtime.getConfig();
173        if (action == config.deoptActionNone) {
174            return DeoptimizationAction.None;
175        }
176        if (action == config.deoptActionMaybeRecompile) {
177            return DeoptimizationAction.RecompileIfTooManyDeopts;
178        }
179        if (action == config.deoptActionReinterpret) {
180            return DeoptimizationAction.InvalidateReprofile;
181        }
182        if (action == config.deoptActionMakeNotEntrant) {
183            return DeoptimizationAction.InvalidateRecompile;
184        }
185        if (action == config.deoptActionMakeNotCompilable) {
186            return DeoptimizationAction.InvalidateStopCompiling;
187        }
188        throw new JVMCIError("%d", action);
189    }
190
191    public int convertDeoptReason(DeoptimizationReason reason) {
192        HotSpotVMConfig config = runtime.getConfig();
193        switch (reason) {
194            case None:
195                return config.deoptReasonNone;
196            case NullCheckException:
197                return config.deoptReasonNullCheck;
198            case BoundsCheckException:
199                return config.deoptReasonRangeCheck;
200            case ClassCastException:
201                return config.deoptReasonClassCheck;
202            case ArrayStoreException:
203                return config.deoptReasonArrayCheck;
204            case UnreachedCode:
205                return config.deoptReasonUnreached0;
206            case TypeCheckedInliningViolated:
207                return config.deoptReasonTypeCheckInlining;
208            case OptimizedTypeCheckViolated:
209                return config.deoptReasonOptimizedTypeCheck;
210            case NotCompiledExceptionHandler:
211                return config.deoptReasonNotCompiledExceptionHandler;
212            case Unresolved:
213                return config.deoptReasonUnresolved;
214            case JavaSubroutineMismatch:
215                return config.deoptReasonJsrMismatch;
216            case ArithmeticException:
217                return config.deoptReasonDiv0Check;
218            case RuntimeConstraint:
219                return config.deoptReasonConstraint;
220            case LoopLimitCheck:
221                return config.deoptReasonLoopLimitCheck;
222            case Aliasing:
223                return config.deoptReasonAliasing;
224            case TransferToInterpreter:
225                return config.deoptReasonTransferToInterpreter;
226            default:
227                throw new JVMCIError("%s", reason);
228        }
229    }
230
231    public DeoptimizationReason convertDeoptReason(int reason) {
232        HotSpotVMConfig config = runtime.getConfig();
233        if (reason == config.deoptReasonNone) {
234            return DeoptimizationReason.None;
235        }
236        if (reason == config.deoptReasonNullCheck) {
237            return DeoptimizationReason.NullCheckException;
238        }
239        if (reason == config.deoptReasonRangeCheck) {
240            return DeoptimizationReason.BoundsCheckException;
241        }
242        if (reason == config.deoptReasonClassCheck) {
243            return DeoptimizationReason.ClassCastException;
244        }
245        if (reason == config.deoptReasonArrayCheck) {
246            return DeoptimizationReason.ArrayStoreException;
247        }
248        if (reason == config.deoptReasonUnreached0) {
249            return DeoptimizationReason.UnreachedCode;
250        }
251        if (reason == config.deoptReasonTypeCheckInlining) {
252            return DeoptimizationReason.TypeCheckedInliningViolated;
253        }
254        if (reason == config.deoptReasonOptimizedTypeCheck) {
255            return DeoptimizationReason.OptimizedTypeCheckViolated;
256        }
257        if (reason == config.deoptReasonNotCompiledExceptionHandler) {
258            return DeoptimizationReason.NotCompiledExceptionHandler;
259        }
260        if (reason == config.deoptReasonUnresolved) {
261            return DeoptimizationReason.Unresolved;
262        }
263        if (reason == config.deoptReasonJsrMismatch) {
264            return DeoptimizationReason.JavaSubroutineMismatch;
265        }
266        if (reason == config.deoptReasonDiv0Check) {
267            return DeoptimizationReason.ArithmeticException;
268        }
269        if (reason == config.deoptReasonConstraint) {
270            return DeoptimizationReason.RuntimeConstraint;
271        }
272        if (reason == config.deoptReasonLoopLimitCheck) {
273            return DeoptimizationReason.LoopLimitCheck;
274        }
275        if (reason == config.deoptReasonAliasing) {
276            return DeoptimizationReason.Aliasing;
277        }
278        if (reason == config.deoptReasonTransferToInterpreter) {
279            return DeoptimizationReason.TransferToInterpreter;
280        }
281        throw new JVMCIError("%x", reason);
282    }
283
284    @Override
285    public long getMemorySize(JavaConstant constant) {
286        if (constant.getKind() == Kind.Object) {
287            HotSpotResolvedObjectType lookupJavaType = lookupJavaType(constant);
288
289            if (lookupJavaType == null) {
290                return 0;
291            } else {
292                if (lookupJavaType.isArray()) {
293                    // TODO(tw): Add compressed pointer support.
294                    int length = Array.getLength(((HotSpotObjectConstantImpl) constant).object());
295                    ResolvedJavaType elementType = lookupJavaType.getComponentType();
296                    Kind elementKind = elementType.getKind();
297                    final int headerSize = runtime.getArrayBaseOffset(elementKind);
298                    TargetDescription target = runtime.getHostJVMCIBackend().getTarget();
299                    int sizeOfElement = target.getSizeInBytes(elementKind);
300                    int alignment = target.wordSize;
301                    int log2ElementSize = CodeUtil.log2(sizeOfElement);
302                    return computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize);
303                }
304                return lookupJavaType.instanceSize();
305            }
306        } else {
307            return constant.getKind().getByteCount();
308        }
309    }
310
311    /**
312     * Computes the size of the memory chunk allocated for an array. This size accounts for the
313     * array header size, body size and any padding after the last element to satisfy object
314     * alignment requirements.
315     *
316     * @param length the number of elements in the array
317     * @param alignment the object alignment requirement
318     * @param headerSize the size of the array header
319     * @param log2ElementSize log2 of the size of an element in the array
320     */
321    public static int computeArrayAllocationSize(int length, int alignment, int headerSize, int log2ElementSize) {
322        int size = (length << log2ElementSize) + headerSize + (alignment - 1);
323        int mask = ~(alignment - 1);
324        return size & mask;
325    }
326}