comparison graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/HotSpotResolvedJavaMethodImpl.java @ 21551:5324104ac4f3

moved com.oracle.graal.hotspot.jvmci classes to com.oracle.jvmci.hotspot module (JBS:GRAAL-53)
author Doug Simon <doug.simon@oracle.com>
date Tue, 26 May 2015 17:13:37 +0200
parents
children
comparison
equal deleted inserted replaced
21550:f48a6cea31eb 21551:5324104ac4f3
1 /*
2 * Copyright (c) 2011, 2014, 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 package com.oracle.jvmci.hotspot;
24
25 import static com.oracle.jvmci.common.UnsafeAccess.*;
26 import static com.oracle.jvmci.hotspot.HotSpotJVMCIRuntime.*;
27 import static com.oracle.jvmci.hotspot.HotSpotResolvedJavaMethodImpl.Options.*;
28
29 import java.lang.annotation.*;
30 import java.lang.reflect.*;
31 import java.util.*;
32
33 import com.oracle.graal.api.code.*;
34 import com.oracle.graal.api.meta.*;
35 import com.oracle.graal.debug.*;
36 import com.oracle.graal.options.*;
37 import com.oracle.jvmci.common.*;
38
39 /**
40 * Implementation of {@link JavaMethod} for resolved HotSpot methods.
41 */
42 public final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSpotResolvedJavaMethod, HotSpotProxified, MethodIdHolder {
43
44 static class Options {
45 // @formatter:off
46 @Option(help = "", type = OptionType.Debug)
47 public static final OptionValue<Boolean> UseProfilingInformation = new OptionValue<>(true);
48 // @formatter:on
49 }
50
51 /**
52 * Reference to metaspace Method object.
53 */
54 private final long metaspaceMethod;
55
56 private final HotSpotResolvedObjectTypeImpl holder;
57 private final HotSpotConstantPool constantPool;
58 private final HotSpotSignature signature;
59 private HotSpotMethodData methodData;
60 private byte[] code;
61 private Member toJavaCache;
62
63 /**
64 * Gets the holder of a HotSpot metaspace method native object.
65 *
66 * @param metaspaceMethod a metaspace Method object
67 * @return the {@link ResolvedJavaType} corresponding to the holder of the
68 * {@code metaspaceMethod}
69 */
70 public static HotSpotResolvedObjectTypeImpl getHolder(long metaspaceMethod) {
71 HotSpotVMConfig config = runtime().getConfig();
72 final long metaspaceConstMethod = unsafe.getAddress(metaspaceMethod + config.methodConstMethodOffset);
73 final long metaspaceConstantPool = unsafe.getAddress(metaspaceConstMethod + config.constMethodConstantsOffset);
74 final long metaspaceKlass = unsafe.getAddress(metaspaceConstantPool + config.constantPoolHolderOffset);
75 return HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(metaspaceKlass);
76 }
77
78 /**
79 * Gets the {@link ResolvedJavaMethod} for a HotSpot metaspace method native object.
80 *
81 * @param metaspaceMethod a metaspace Method object
82 * @return the {@link ResolvedJavaMethod} corresponding to {@code metaspaceMethod}
83 */
84 public static HotSpotResolvedJavaMethod fromMetaspace(long metaspaceMethod) {
85 HotSpotResolvedObjectTypeImpl holder = getHolder(metaspaceMethod);
86 return holder.createMethod(metaspaceMethod);
87 }
88
89 public HotSpotResolvedJavaMethodImpl(HotSpotResolvedObjectTypeImpl holder, long metaspaceMethod) {
90 // It would be too much work to get the method name here so we fill it in later.
91 super(null);
92 this.metaspaceMethod = metaspaceMethod;
93 this.holder = holder;
94
95 HotSpotVMConfig config = runtime().getConfig();
96 final long constMethod = getConstMethod();
97
98 /*
99 * Get the constant pool from the metaspace method. Some methods (e.g. intrinsics for
100 * signature-polymorphic method handle methods) have their own constant pool instead of the
101 * one from their holder.
102 */
103 final long metaspaceConstantPool = unsafe.getAddress(constMethod + config.constMethodConstantsOffset);
104 this.constantPool = new HotSpotConstantPool(metaspaceConstantPool);
105
106 final int nameIndex = unsafe.getChar(constMethod + config.constMethodNameIndexOffset);
107 this.name = constantPool.lookupUtf8(nameIndex);
108
109 final int signatureIndex = unsafe.getChar(constMethod + config.constMethodSignatureIndexOffset);
110 this.signature = (HotSpotSignature) constantPool.lookupSignature(signatureIndex);
111 }
112
113 /**
114 * Returns a pointer to this method's constant method data structure (
115 * {@code Method::_constMethod}).
116 *
117 * @return pointer to this method's ConstMethod
118 */
119 private long getConstMethod() {
120 assert metaspaceMethod != 0;
121 return unsafe.getAddress(metaspaceMethod + runtime().getConfig().methodConstMethodOffset);
122 }
123
124 @Override
125 public boolean equals(Object obj) {
126 if (obj instanceof HotSpotResolvedJavaMethodImpl) {
127 HotSpotResolvedJavaMethodImpl that = (HotSpotResolvedJavaMethodImpl) obj;
128 return that.metaspaceMethod == metaspaceMethod;
129 }
130 return false;
131 }
132
133 @Override
134 public int hashCode() {
135 return (int) metaspaceMethod;
136 }
137
138 /**
139 * Returns this method's flags ({@code Method::_flags}).
140 *
141 * @return flags of this method
142 */
143 private int getFlags() {
144 return unsafe.getByte(metaspaceMethod + runtime().getConfig().methodFlagsOffset);
145 }
146
147 /**
148 * Returns this method's constant method flags ({@code ConstMethod::_flags}).
149 *
150 * @return flags of this method's ConstMethod
151 */
152 private int getConstMethodFlags() {
153 return unsafe.getChar(getConstMethod() + runtime().getConfig().constMethodFlagsOffset);
154 }
155
156 @Override
157 public HotSpotResolvedObjectTypeImpl getDeclaringClass() {
158 return holder;
159 }
160
161 /**
162 * Gets the address of the C++ Method object for this method.
163 */
164 public JavaConstant getMetaspaceMethodConstant() {
165 return HotSpotMetaspaceConstantImpl.forMetaspaceObject(getHostWordKind(), metaspaceMethod, this, false);
166 }
167
168 public long getMetaspaceMethod() {
169 return metaspaceMethod;
170 }
171
172 @Override
173 public JavaConstant getEncoding() {
174 return getMetaspaceMethodConstant();
175 }
176
177 /**
178 * Gets the complete set of modifiers for this method which includes the JVM specification
179 * modifiers as well as the HotSpot internal modifiers.
180 */
181 public int getAllModifiers() {
182 return unsafe.getInt(metaspaceMethod + runtime().getConfig().methodAccessFlagsOffset);
183 }
184
185 @Override
186 public int getModifiers() {
187 return getAllModifiers() & Modifier.methodModifiers();
188 }
189
190 @Override
191 public boolean canBeStaticallyBound() {
192 return (isFinal() || isPrivate() || isStatic() || holder.isFinal()) && isConcrete();
193 }
194
195 @Override
196 public byte[] getCode() {
197 if (getCodeSize() == 0) {
198 return null;
199 }
200 if (code == null && holder.isLinked()) {
201 code = runtime().getCompilerToVM().getBytecode(metaspaceMethod);
202 assert code.length == getCodeSize() : "expected: " + getCodeSize() + ", actual: " + code.length;
203 }
204 return code;
205 }
206
207 @Override
208 public int getCodeSize() {
209 return unsafe.getChar(getConstMethod() + runtime().getConfig().constMethodCodeSizeOffset);
210 }
211
212 @Override
213 public ExceptionHandler[] getExceptionHandlers() {
214 final boolean hasExceptionTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasExceptionTable) != 0;
215 if (!hasExceptionTable) {
216 return new ExceptionHandler[0];
217 }
218
219 HotSpotVMConfig config = runtime().getConfig();
220 final int exceptionTableLength = runtime().getCompilerToVM().exceptionTableLength(metaspaceMethod);
221 ExceptionHandler[] handlers = new ExceptionHandler[exceptionTableLength];
222 long exceptionTableElement = runtime().getCompilerToVM().exceptionTableStart(metaspaceMethod);
223
224 for (int i = 0; i < exceptionTableLength; i++) {
225 final int startPc = unsafe.getChar(exceptionTableElement + config.exceptionTableElementStartPcOffset);
226 final int endPc = unsafe.getChar(exceptionTableElement + config.exceptionTableElementEndPcOffset);
227 final int handlerPc = unsafe.getChar(exceptionTableElement + config.exceptionTableElementHandlerPcOffset);
228 int catchTypeIndex = unsafe.getChar(exceptionTableElement + config.exceptionTableElementCatchTypeIndexOffset);
229
230 JavaType catchType;
231 if (catchTypeIndex == 0) {
232 catchType = null;
233 } else {
234 final int opcode = -1; // opcode is not used
235 catchType = constantPool.lookupType(catchTypeIndex, opcode);
236
237 // Check for Throwable which catches everything.
238 if (catchType instanceof HotSpotResolvedObjectTypeImpl) {
239 HotSpotResolvedObjectTypeImpl resolvedType = (HotSpotResolvedObjectTypeImpl) catchType;
240 if (resolvedType.mirror() == Throwable.class) {
241 catchTypeIndex = 0;
242 catchType = null;
243 }
244 }
245 }
246 handlers[i] = new ExceptionHandler(startPc, endPc, handlerPc, catchTypeIndex, catchType);
247
248 // Go to the next ExceptionTableElement
249 exceptionTableElement += config.exceptionTableElementSize;
250 }
251
252 return handlers;
253 }
254
255 /**
256 * Returns true if this method has a {@code CallerSensitive} annotation.
257 *
258 * @return true if CallerSensitive annotation present, false otherwise
259 */
260 public boolean isCallerSensitive() {
261 return (getFlags() & runtime().getConfig().methodFlagsCallerSensitive) != 0;
262 }
263
264 /**
265 * Returns true if this method has a {@code ForceInline} annotation.
266 *
267 * @return true if ForceInline annotation present, false otherwise
268 */
269 public boolean isForceInline() {
270 return (getFlags() & runtime().getConfig().methodFlagsForceInline) != 0;
271 }
272
273 /**
274 * Returns true if this method has a {@code DontInline} annotation.
275 *
276 * @return true if DontInline annotation present, false otherwise
277 */
278 public boolean isDontInline() {
279 return (getFlags() & runtime().getConfig().methodFlagsDontInline) != 0;
280 }
281
282 /**
283 * Manually adds a DontInline annotation to this method.
284 */
285 public void setNotInlineable() {
286 runtime().getCompilerToVM().doNotInlineOrCompile(metaspaceMethod);
287 }
288
289 /**
290 * Returns true if this method is one of the special methods that is ignored by security stack
291 * walks.
292 *
293 * @return true if special method ignored by security stack walks, false otherwise
294 */
295 public boolean ignoredBySecurityStackWalk() {
296 return runtime().getCompilerToVM().methodIsIgnoredBySecurityStackWalk(metaspaceMethod);
297 }
298
299 public boolean hasBalancedMonitors() {
300 HotSpotVMConfig config = runtime().getConfig();
301 final int modifiers = getAllModifiers();
302
303 // Method has no monitorenter/exit bytecodes.
304 if ((modifiers & config.jvmAccHasMonitorBytecodes) == 0) {
305 return false;
306 }
307
308 // Check to see if a previous compilation computed the monitor-matching analysis.
309 if ((modifiers & config.jvmAccMonitorMatch) != 0) {
310 return true;
311 }
312
313 // This either happens only once if monitors are balanced or very rarely multiple-times.
314 return runtime().getCompilerToVM().hasBalancedMonitors(metaspaceMethod);
315 }
316
317 @Override
318 public boolean isClassInitializer() {
319 return "<clinit>".equals(name) && isStatic();
320 }
321
322 @Override
323 public boolean isConstructor() {
324 return "<init>".equals(name) && !isStatic();
325 }
326
327 @Override
328 public int getMaxLocals() {
329 if (isAbstract() || isNative()) {
330 return 0;
331 }
332 HotSpotVMConfig config = runtime().getConfig();
333 return unsafe.getChar(getConstMethod() + config.methodMaxLocalsOffset);
334 }
335
336 @Override
337 public int getMaxStackSize() {
338 if (isAbstract() || isNative()) {
339 return 0;
340 }
341 HotSpotVMConfig config = runtime().getConfig();
342 return config.extraStackEntries + unsafe.getChar(getConstMethod() + config.constMethodMaxStackOffset);
343 }
344
345 @Override
346 public StackTraceElement asStackTraceElement(int bci) {
347 if (bci < 0 || bci >= getCodeSize()) {
348 // HotSpot code can only construct stack trace elements for valid bcis
349 StackTraceElement ste = runtime().getCompilerToVM().getStackTraceElement(metaspaceMethod, 0);
350 return new StackTraceElement(ste.getClassName(), ste.getMethodName(), ste.getFileName(), -1);
351 }
352 return runtime().getCompilerToVM().getStackTraceElement(metaspaceMethod, bci);
353 }
354
355 public ResolvedJavaMethod uniqueConcreteMethod(HotSpotResolvedObjectType receiver) {
356 if (receiver.isInterface()) {
357 // Cannot trust interfaces. Because of:
358 // interface I { void foo(); }
359 // class A { public void foo() {} }
360 // class B extends A implements I { }
361 // class C extends B { public void foo() { } }
362 // class D extends B { }
363 // Would lead to identify C.foo() as the unique concrete method for I.foo() without
364 // seeing A.foo().
365 return null;
366 }
367 long metaspaceKlass = ((HotSpotResolvedObjectTypeImpl) receiver).getMetaspaceKlass();
368 final long uniqueConcreteMethod = runtime().getCompilerToVM().findUniqueConcreteMethod(metaspaceKlass, metaspaceMethod);
369 if (uniqueConcreteMethod == 0) {
370 return null;
371 }
372 return fromMetaspace(uniqueConcreteMethod);
373 }
374
375 @Override
376 public HotSpotSignature getSignature() {
377 return signature;
378 }
379
380 /**
381 * Gets the value of {@code Method::_code}.
382 *
383 * @return the value of {@code Method::_code}
384 */
385 private long getCompiledCode() {
386 HotSpotVMConfig config = runtime().getConfig();
387 return unsafe.getAddress(metaspaceMethod + config.methodCodeOffset);
388 }
389
390 /**
391 * Returns whether this method has compiled code.
392 *
393 * @return true if this method has compiled code, false otherwise
394 */
395 public boolean hasCompiledCode() {
396 return getCompiledCode() != 0L;
397 }
398
399 /**
400 * @param level
401 * @return true if the currently installed code was generated at {@code level}.
402 */
403 public boolean hasCompiledCodeAtLevel(int level) {
404 long compiledCode = getCompiledCode();
405 if (compiledCode != 0) {
406 return unsafe.getInt(compiledCode + runtime().getConfig().nmethodCompLevelOffset) == level;
407 }
408 return false;
409 }
410
411 private static final String TraceMethodDataFilter = System.getProperty("graal.traceMethodDataFilter");
412
413 @Override
414 public ProfilingInfo getProfilingInfo() {
415 return getProfilingInfo(true, true);
416 }
417
418 public ProfilingInfo getCompilationProfilingInfo(boolean isOSR) {
419 return getProfilingInfo(!isOSR, isOSR);
420 }
421
422 private ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) {
423 ProfilingInfo info;
424
425 if (UseProfilingInformation.getValue() && methodData == null) {
426 long metaspaceMethodData = unsafe.getAddress(metaspaceMethod + runtime().getConfig().methodDataOffset);
427 if (metaspaceMethodData != 0) {
428 methodData = new HotSpotMethodData(metaspaceMethodData);
429 if (TraceMethodDataFilter != null && this.format("%H.%n").contains(TraceMethodDataFilter)) {
430 TTY.println("Raw method data for " + this.format("%H.%n(%p)") + ":");
431 TTY.println(methodData.toString());
432 }
433 }
434 }
435
436 if (methodData == null || (!methodData.hasNormalData() && !methodData.hasExtraData())) {
437 // Be optimistic and return false for exceptionSeen. A methodDataOop is allocated in
438 // case of a deoptimization.
439 info = DefaultProfilingInfo.get(TriState.FALSE);
440 } else {
441 info = new HotSpotProfilingInfo(methodData, this, includeNormal, includeOSR);
442 }
443 return info;
444 }
445
446 @Override
447 public void reprofile() {
448 runtime().getCompilerToVM().reprofile(metaspaceMethod);
449 }
450
451 @Override
452 public ConstantPool getConstantPool() {
453 return constantPool;
454 }
455
456 @Override
457 public Annotation[][] getParameterAnnotations() {
458 if (isConstructor()) {
459 Constructor<?> javaConstructor = toJavaConstructor();
460 return javaConstructor == null ? null : javaConstructor.getParameterAnnotations();
461 }
462 Method javaMethod = toJava();
463 return javaMethod == null ? null : javaMethod.getParameterAnnotations();
464 }
465
466 @Override
467 public Annotation[] getAnnotations() {
468 if (isConstructor()) {
469 Constructor<?> javaConstructor = toJavaConstructor();
470 return javaConstructor == null ? new Annotation[0] : javaConstructor.getAnnotations();
471 }
472 Method javaMethod = toJava();
473 return javaMethod == null ? new Annotation[0] : javaMethod.getAnnotations();
474 }
475
476 @Override
477 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
478 if (isConstructor()) {
479 Constructor<?> javaConstructor = toJavaConstructor();
480 return javaConstructor == null ? null : javaConstructor.getAnnotation(annotationClass);
481 }
482 Method javaMethod = toJava();
483 return javaMethod == null ? null : javaMethod.getAnnotation(annotationClass);
484 }
485
486 @Override
487 public boolean isSynthetic() {
488 int modifiers = getAllModifiers();
489 return (runtime().getConfig().syntheticFlag & modifiers) != 0;
490 }
491
492 public boolean isDefault() {
493 if (isConstructor()) {
494 return false;
495 }
496 // Copied from java.lang.Method.isDefault()
497 int mask = Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC;
498 return ((getModifiers() & mask) == Modifier.PUBLIC) && getDeclaringClass().isInterface();
499 }
500
501 @Override
502 public Type[] getGenericParameterTypes() {
503 if (isConstructor()) {
504 Constructor<?> javaConstructor = toJavaConstructor();
505 return javaConstructor == null ? null : javaConstructor.getGenericParameterTypes();
506 }
507 Method javaMethod = toJava();
508 return javaMethod == null ? null : javaMethod.getGenericParameterTypes();
509 }
510
511 public Class<?>[] signatureToTypes() {
512 Signature sig = getSignature();
513 int count = sig.getParameterCount(false);
514 Class<?>[] result = new Class<?>[count];
515 for (int i = 0; i < result.length; ++i) {
516 JavaType parameterType = sig.getParameterType(i, holder);
517 HotSpotResolvedJavaType resolvedParameterType = (HotSpotResolvedJavaType) parameterType.resolve(holder);
518 result[i] = resolvedParameterType.mirror();
519 }
520 return result;
521 }
522
523 private Method toJava() {
524 if (toJavaCache != null) {
525 return (Method) toJavaCache;
526 }
527 try {
528 Method result = holder.mirror().getDeclaredMethod(name, signatureToTypes());
529 toJavaCache = result;
530 return result;
531 } catch (NoSuchMethodException | NoClassDefFoundError e) {
532 return null;
533 }
534 }
535
536 private Constructor<?> toJavaConstructor() {
537 if (toJavaCache != null) {
538 return (Constructor<?>) toJavaCache;
539 }
540 try {
541 Constructor<?> result = holder.mirror().getDeclaredConstructor(signatureToTypes());
542 toJavaCache = result;
543 return result;
544 } catch (NoSuchMethodException | NoClassDefFoundError e) {
545 return null;
546 }
547 }
548
549 @Override
550 public boolean canBeInlined() {
551 if (isDontInline()) {
552 return false;
553 }
554 return runtime().getCompilerToVM().canInlineMethod(metaspaceMethod);
555 }
556
557 @Override
558 public boolean shouldBeInlined() {
559 if (isForceInline()) {
560 return true;
561 }
562 return runtime().getCompilerToVM().shouldInlineMethod(metaspaceMethod);
563 }
564
565 @Override
566 public LineNumberTable getLineNumberTable() {
567 final boolean hasLineNumberTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasLineNumberTable) != 0;
568 if (!hasLineNumberTable) {
569 return null;
570 }
571
572 long[] values = runtime().getCompilerToVM().getLineNumberTable(metaspaceMethod);
573 if (values.length == 0) {
574 // Empty table so treat is as non-existent
575 return null;
576 }
577 assert values.length % 2 == 0;
578 int[] bci = new int[values.length / 2];
579 int[] line = new int[values.length / 2];
580
581 for (int i = 0; i < values.length / 2; i++) {
582 bci[i] = (int) values[i * 2];
583 line[i] = (int) values[i * 2 + 1];
584 }
585
586 return new LineNumberTableImpl(line, bci);
587 }
588
589 @Override
590 public LocalVariableTable getLocalVariableTable() {
591 final boolean hasLocalVariableTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasLocalVariableTable) != 0;
592 if (!hasLocalVariableTable) {
593 return null;
594 }
595
596 HotSpotVMConfig config = runtime().getConfig();
597 long localVariableTableElement = runtime().getCompilerToVM().getLocalVariableTableStart(metaspaceMethod);
598 final int localVariableTableLength = runtime().getCompilerToVM().getLocalVariableTableLength(metaspaceMethod);
599 Local[] locals = new Local[localVariableTableLength];
600
601 for (int i = 0; i < localVariableTableLength; i++) {
602 final int startBci = unsafe.getChar(localVariableTableElement + config.localVariableTableElementStartBciOffset);
603 final int endBci = startBci + unsafe.getChar(localVariableTableElement + config.localVariableTableElementLengthOffset);
604 final int nameCpIndex = unsafe.getChar(localVariableTableElement + config.localVariableTableElementNameCpIndexOffset);
605 final int typeCpIndex = unsafe.getChar(localVariableTableElement + config.localVariableTableElementDescriptorCpIndexOffset);
606 final int slot = unsafe.getChar(localVariableTableElement + config.localVariableTableElementSlotOffset);
607
608 String localName = getConstantPool().lookupUtf8(nameCpIndex);
609 String localType = getConstantPool().lookupUtf8(typeCpIndex);
610
611 locals[i] = new LocalImpl(localName, runtime().lookupType(localType, holder, false), startBci, endBci, slot);
612
613 // Go to the next LocalVariableTableElement
614 localVariableTableElement += config.localVariableTableElementSize;
615 }
616
617 return new LocalVariableTableImpl(locals);
618 }
619
620 /**
621 * Returns the offset of this method into the v-table. The method must have a v-table entry as
622 * indicated by {@link #isInVirtualMethodTable(ResolvedJavaType)}, otherwise an exception is
623 * thrown.
624 *
625 * @return the offset of this method into the v-table
626 */
627 public int vtableEntryOffset(ResolvedJavaType resolved) {
628 if (!isInVirtualMethodTable(resolved)) {
629 throw new JVMCIError("%s does not have a vtable entry", this);
630 }
631 HotSpotVMConfig config = runtime().getConfig();
632 final int vtableIndex = getVtableIndex((HotSpotResolvedObjectTypeImpl) resolved);
633 return config.instanceKlassVtableStartOffset + vtableIndex * config.vtableEntrySize + config.vtableEntryMethodOffset;
634 }
635
636 @Override
637 public boolean isInVirtualMethodTable(ResolvedJavaType resolved) {
638 if (resolved instanceof HotSpotResolvedObjectTypeImpl) {
639 HotSpotResolvedObjectTypeImpl hotspotResolved = (HotSpotResolvedObjectTypeImpl) resolved;
640 int vtableIndex = getVtableIndex(hotspotResolved);
641 return vtableIndex >= 0 && vtableIndex < hotspotResolved.getVtableLength();
642 }
643 return false;
644 }
645
646 private int getVtableIndex(HotSpotResolvedObjectTypeImpl resolved) {
647 if (!holder.isLinked()) {
648 return runtime().getConfig().invalidVtableIndex;
649 }
650 if (holder.isInterface()) {
651 if (resolved.isInterface()) {
652 return runtime().getConfig().invalidVtableIndex;
653 }
654 return getVtableIndexForInterface(resolved);
655 }
656 return getVtableIndex();
657 }
658
659 /**
660 * Returns this method's virtual table index.
661 *
662 * @return virtual table index
663 */
664 private int getVtableIndex() {
665 assert !holder.isInterface();
666 HotSpotVMConfig config = runtime().getConfig();
667 int result = unsafe.getInt(metaspaceMethod + config.methodVtableIndexOffset);
668 assert result >= config.nonvirtualVtableIndex : "must be linked";
669 return result;
670 }
671
672 private int getVtableIndexForInterface(ResolvedJavaType resolved) {
673 HotSpotResolvedObjectTypeImpl hotspotType = (HotSpotResolvedObjectTypeImpl) resolved;
674 return runtime().getCompilerToVM().getVtableIndexForInterface(hotspotType.getMetaspaceKlass(), getMetaspaceMethod());
675 }
676
677 /**
678 * The {@link SpeculationLog} for methods compiled by Graal hang off this per-declaring-type
679 * {@link ClassValue}. The raw Method* value is safe to use as a key in the map as a) it is
680 * never moves and b) we never read from it.
681 * <p>
682 * One implication is that we will preserve {@link SpeculationLog}s for methods that have been
683 * redefined via class redefinition. It's tempting to periodically flush such logs but we cannot
684 * read the JVM_ACC_IS_OBSOLETE bit (or anything else) via the raw pointer as obsoleted methods
685 * are subject to clean up and deletion (see InstanceKlass::purge_previous_versions_internal).
686 */
687 private static final ClassValue<Map<Long, SpeculationLog>> SpeculationLogs = new ClassValue<Map<Long, SpeculationLog>>() {
688 @Override
689 protected Map<Long, SpeculationLog> computeValue(java.lang.Class<?> type) {
690 return new HashMap<>(4);
691 }
692 };
693
694 public SpeculationLog getSpeculationLog() {
695 Map<Long, SpeculationLog> map = SpeculationLogs.get(holder.mirror());
696 synchronized (map) {
697 SpeculationLog log = map.get(this.metaspaceMethod);
698 if (log == null) {
699 log = new HotSpotSpeculationLog();
700 map.put(metaspaceMethod, log);
701 }
702 return log;
703 }
704 }
705
706 public int intrinsicId() {
707 HotSpotVMConfig config = runtime().getConfig();
708 return unsafe.getByte(metaspaceMethod + config.methodIntrinsicIdOffset) & 0xff;
709 }
710
711 @Override
712 public JavaConstant invoke(JavaConstant receiver, JavaConstant[] arguments) {
713 assert !isConstructor();
714 Method javaMethod = toJava();
715 javaMethod.setAccessible(true);
716
717 Object[] objArguments = new Object[arguments.length];
718 for (int i = 0; i < arguments.length; i++) {
719 objArguments[i] = HotSpotObjectConstantImpl.asBoxedValue(arguments[i]);
720 }
721 Object objReceiver = receiver != null && !receiver.isNull() ? ((HotSpotObjectConstantImpl) receiver).object() : null;
722
723 try {
724 Object objResult = javaMethod.invoke(objReceiver, objArguments);
725 return javaMethod.getReturnType() == void.class ? null : HotSpotObjectConstantImpl.forBoxedValue(getSignature().getReturnKind(), objResult);
726
727 } catch (IllegalAccessException | InvocationTargetException ex) {
728 throw new IllegalArgumentException(ex);
729 }
730 }
731
732 /**
733 * Allocates a compile id for this method by asking the VM for one.
734 *
735 * @param entryBCI entry bci
736 * @return compile id
737 */
738 public int allocateCompileId(int entryBCI) {
739 return runtime().getCompilerToVM().allocateCompileId(metaspaceMethod, entryBCI);
740 }
741
742 public boolean hasCodeAtLevel(int entryBCI, int level) {
743 if (entryBCI == runtime().getConfig().invocationEntryBci) {
744 return hasCompiledCodeAtLevel(level);
745 }
746 return runtime().getCompilerToVM().hasCompiledCodeForOSR(metaspaceMethod, entryBCI, level);
747 }
748
749 private int methodId;
750
751 public void setMethodId(int id) {
752 assert methodId == 0;
753 methodId = id;
754 }
755
756 public int getMethodId() {
757 return methodId;
758 }
759 }