Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
*/
package com.oracle.svm.core.graal.snippets;

import static com.oracle.svm.core.hub.DynamicHubTypeCheckUtil.HASHING_INTERFACE_MASK;
import static com.oracle.svm.core.hub.DynamicHubTypeCheckUtil.HASHING_ITABLE_SHIFT;
import static com.oracle.svm.core.hub.DynamicHubTypeCheckUtil.HASHING_SHIFT_OFFSET;
import static com.oracle.svm.core.hub.DynamicHubUtils.HASHING_INTERFACE_MASK;
import static com.oracle.svm.core.hub.DynamicHubUtils.HASHING_ITABLE_SHIFT;
import static com.oracle.svm.core.hub.DynamicHubUtils.HASHING_SHIFT_OFFSET;
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.probability;
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.unknownProbability;

Expand All @@ -40,7 +40,7 @@
import com.oracle.svm.core.graal.meta.KnownOffsets;
import com.oracle.svm.core.graal.nodes.LoadOpenTypeWorldDispatchTableStartingOffset;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.hub.DynamicHubTypeCheckUtil;
import com.oracle.svm.core.hub.DynamicHubUtils;
import com.oracle.svm.core.meta.SharedMethod;
import com.oracle.svm.core.meta.SharedType;

Expand Down Expand Up @@ -119,9 +119,8 @@ private static long determineITableStartingOffsetIterative(
* If {@link SubstrateOptions#useInterfaceHashing()} is enabled, interfaceIDs and itable
* starting offsets are stored in a hash table (see TypeCheckBuilder for a general
* documentation). This snippet handles the lookup in the hash table and returns the itable
* starting offset for the given interfaceID. See
* {@link DynamicHubTypeCheckUtil#hashParam(int[])} for details on the hashing function and
* hashing parameter.
* starting offset for the given interfaceID. See {@link DynamicHubUtils#hashParam(int[])} for
* details on the hashing function and hashing parameter.
*/
private static int determineITableStartingOffsetHashed(
DynamicHub checkedHub,
Expand Down Expand Up @@ -149,7 +148,7 @@ private static int determineITableStartingOffsetHashed(
public static long determineITableStartingOffset(
DynamicHub checkedHub,
int interfaceID) {
if (SubstrateOptions.useInterfaceHashing()) {
if (SubstrateOptions.useInterfaceHashing() && interfaceID <= SubstrateOptions.interfaceHashingMaxId()) {
// Use the non-snippet version which contains no snippet asserts.
return determineITableStartingOffsetHashedNonSnippet(checkedHub, interfaceID);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@

import static com.oracle.svm.core.graal.snippets.SubstrateIntrinsics.loadHub;
import static com.oracle.svm.core.graal.snippets.SubstrateIntrinsics.loadHubOrNull;
import static com.oracle.svm.core.hub.DynamicHubTypeCheckUtil.HASHING_INTERFACE_MASK;
import static com.oracle.svm.core.hub.DynamicHubTypeCheckUtil.HASHING_SHIFT_OFFSET;
import static com.oracle.svm.core.hub.DynamicHubUtils.HASHING_INTERFACE_MASK;
import static com.oracle.svm.core.hub.DynamicHubUtils.HASHING_SHIFT_OFFSET;
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.probability;
import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.unknownProbability;
Expand All @@ -39,7 +39,7 @@
import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.config.ObjectLayout;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.hub.DynamicHubTypeCheckUtil;
import com.oracle.svm.core.hub.DynamicHubUtils;
import com.oracle.svm.core.meta.SharedType;
import com.oracle.svm.core.util.DuplicatedInNativeCode;

Expand Down Expand Up @@ -235,8 +235,8 @@ protected static SubstrateIntrinsics.Any iterativeInterfaceTypeCheck(
* starting offsets are stored in a hash table (see TypeCheckBuilder for a general
* documentation). This snippet does a hash table lookup and returns true if the provided
* interfaceID matches the interfaceID in the hash table, false otherwise. See
* {@link DynamicHubTypeCheckUtil#hashParam(int[])} for details on the hashing function and
* hashing parameter.
* {@link DynamicHubUtils#hashParam(int[])} for details on the hashing function and hashing
* parameter.
*/
@DuplicatedInNativeCode
protected static SubstrateIntrinsics.Any hashedInterfaceTypeCheck(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,18 @@
import java.util.Set;

import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.graal.meta.KnownOffsets;
import com.oracle.svm.core.graal.snippets.OpenTypeWorldDispatchTableSnippets;
import com.oracle.svm.core.util.DuplicatedInNativeCode;

import jdk.graal.compiler.core.common.NumUtil;
import jdk.graal.compiler.debug.GraalError;

/**
* Contains utility for computing type check info for DynamicHubs, such as constants and functions
* needed for {@link SubstrateOptions#useInterfaceHashing()}.
*
* Contains utilities for interacting with DynamicHubs, such as converting vtable indexes to
* dispatch table offsets and calculating metadata needed for typecheck computations.
*/
public final class DynamicHubTypeCheckUtil {
public final class DynamicHubUtils {

// Constants for interface hashing

Expand Down Expand Up @@ -135,7 +136,7 @@ public static TypeCheckData computeOpenTypeWorldTypeCheckData(boolean implements
}

// calculate hash parameter for hashable interfaces
hashParam = DynamicHubTypeCheckUtil.hashParam(hashedInterfaces);
hashParam = DynamicHubUtils.hashParam(hashedInterfaces);
hashTable = new int[(hashParam & HASHING_PARAM_MASK) + 1];
}

Expand All @@ -152,7 +153,7 @@ public static TypeCheckData computeOpenTypeWorldTypeCheckData(boolean implements
if (useInterfaceHashing && interfaceID <= SubstrateOptions.interfaceHashingMaxId()) {
int offset = implementsMethods ? Math.toIntExact(vTableBaseOffset + iTableStartingOffsets[interfaceIdx] * vTableEntrySize) : Short.MIN_VALUE;
GraalError.guarantee(NumUtil.isShort(offset), "ItableDynamicHubOffset cannot be encoded as a short. Try -H:-UseInterfaceHashing.");
hashTable[DynamicHubTypeCheckUtil.hash(interfaceID, hashParam)] = ((offset << HASHING_ITABLE_SHIFT) | interfaceID);
hashTable[DynamicHubUtils.hash(interfaceID, hashParam)] = ((offset << HASHING_ITABLE_SHIFT) | interfaceID);
} else {
int offset = implementsMethods ? Math.toIntExact(vTableBaseOffset + iTableStartingOffsets[interfaceIdx] * vTableEntrySize) : 0xBADD0D1D;
openTypeWorldTypeCheckSlots[iterableInterfaceIdx * 2 + numClassTypes] = interfaceID;
Expand Down Expand Up @@ -255,4 +256,17 @@ private static boolean isValidHashParam(int[] vals, int hashParam, Set<Integer>
}
return true;
}

/**
* Calculates the offset of a virtual call when the receiver is of type {@code thisHub} and the
* target method's declaring class is of type {@code callTargetHub}.
*/
public static int determineDispatchTableOffset(DynamicHub thisHub, DynamicHub callTargetHub, int vTableIndex) {
if (SubstrateOptions.useClosedTypeWorldHubLayout() || !callTargetHub.isInterface()) {
return KnownOffsets.singleton().getVTableOffset(vTableIndex, true);
} else {
int indexOffset = KnownOffsets.singleton().getVTableOffset(vTableIndex, false);
return NumUtil.safeToInt(indexOffset + OpenTypeWorldDispatchTableSnippets.determineITableStartingOffset(thisHub, callTargetHub.getInterfaceID()));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
import com.oracle.svm.core.graal.snippets.OpenTypeWorldSnippets;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.hub.DynamicHubSupport;
import com.oracle.svm.core.hub.DynamicHubTypeCheckUtil;
import com.oracle.svm.core.hub.DynamicHubUtils;
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.hosted.OpenTypeWorldFeature;
Expand Down Expand Up @@ -145,7 +145,7 @@
* entries encode the following:
*
* <pre>
* hashTable[hash(interfaceID)] = (iTableOffset << {@link DynamicHubTypeCheckUtil#HASHING_ITABLE_SHIFT HASHING_ITABLE_OFFSET}) | interfaceID
* hashTable[hash(interfaceID)] = (iTableOffset << {@link DynamicHubUtils#HASHING_ITABLE_SHIFT HASHING_ITABLE_OFFSET}) | interfaceID
* </pre>
*
* Thus, interfaceIDs encoded in hash tables must be > 0, to properly distinguish them from empty
Expand All @@ -154,8 +154,8 @@
* The implementation of the open-world typechecks can be found in {@link OpenTypeWorldSnippets},
* the loading of interface methods can be found in {@link OpenTypeWorldDispatchTableSnippets}. The
* type check data for dynamic hubs is computed in
* {@link DynamicHubTypeCheckUtil#computeOpenTypeWorldTypeCheckData} with the hashing function being
* defined in {@link DynamicHubTypeCheckUtil#hash}.
* {@link DynamicHubUtils#computeOpenTypeWorldTypeCheckData} with the hashing function being defined
* in {@link DynamicHubUtils#hash}.
*/
public final class TypeCheckBuilder {
public static final int UNINITIALIZED_TYPECHECK_SLOTS = -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
import com.oracle.svm.core.heap.SubstrateReferenceMap;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.hub.DynamicHubSupport;
import com.oracle.svm.core.hub.DynamicHubTypeCheckUtil;
import com.oracle.svm.core.hub.DynamicHubUtils;
import com.oracle.svm.core.hub.LayoutEncoding;
import com.oracle.svm.core.imagelayer.DynamicImageLayerInfo;
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
Expand Down Expand Up @@ -1004,7 +1004,7 @@ private void buildHubs() {
}

/**
* See {@link DynamicHubTypeCheckUtil#computeOpenTypeWorldTypeCheckData} for details on the
* See {@link DynamicHubUtils#computeOpenTypeWorldTypeCheckData} for details on the
* {@link DynamicHub} type check layout in the open type world.
*/
private static void setOpenTypeWorldData(HostedType type, DynamicHubLayout dynamicHubLayout, DynamicHub hub, boolean useOffsets) {
Expand All @@ -1020,7 +1020,7 @@ private static void setOpenTypeWorldData(HostedType type, DynamicHubLayout dynam
long vTableOffset = dynamicHubLayout.vTableOffset();
long vTableSlotSize = dynamicHubLayout.vTableSlotSize;

DynamicHubTypeCheckUtil.TypeCheckData typeCheckData = DynamicHubTypeCheckUtil.computeOpenTypeWorldTypeCheckData(implementsMethods, typeHierarchy, interfaceIDs, iTableOffsets, vTableOffset,
DynamicHubUtils.TypeCheckData typeCheckData = DynamicHubUtils.computeOpenTypeWorldTypeCheckData(implementsMethods, typeHierarchy, interfaceIDs, iTableOffsets, vTableOffset,
vTableSlotSize);

MethodRef[] vtable = createVTable(type.openTypeWorldDispatchTables, useOffsets);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -501,17 +501,21 @@ private static Set<HostedType> collectSubtypes(HostedType type, Set<HostedType>
return allSubtypes;
}

private void buildVTable(HostedClass clazz, Map<HostedType, ArrayList<HostedMethod>> vtablesMap, Map<HostedType, BitSet> usedSlotsMap, Map<HostedMethod, Set<Integer>> vtablesSlots) {
private void assignImplementationsAndBuildVTable(HostedClass clazz, Map<HostedType, ArrayList<HostedMethod>> vtablesMap, Map<HostedType, BitSet> usedSlotsMap,
Map<HostedMethod, Set<Integer>> vtablesSlots) {
assignImplementations(clazz, vtablesMap, usedSlotsMap, vtablesSlots);
buildVTable(clazz, vtablesMap, usedSlotsMap, vtablesSlots);
}

private void buildVTable(HostedClass clazz, Map<HostedType, ArrayList<HostedMethod>> vtablesMap, Map<HostedType, BitSet> usedSlotsMap, Map<HostedMethod, Set<Integer>> vtablesSlots) {
ArrayList<HostedMethod> vtable = vtablesMap.get(clazz);
HostedMethod[] vtableArray = vtable.toArray(new HostedMethod[vtable.size()]);
assert vtableArray.length == 0 || vtableArray[vtableArray.length - 1] != null : "Unnecessary entry at end of vtable";
clazz.closedTypeWorldVTable = vtableArray;

for (HostedType subClass : clazz.subTypes) {
if (!subClass.isInterface() && !subClass.isArray()) {
buildVTable((HostedClass) subClass, vtablesMap, usedSlotsMap, vtablesSlots);
assignImplementationsAndBuildVTable((HostedClass) subClass, vtablesMap, usedSlotsMap, vtablesSlots);
}
}
}
Expand Down Expand Up @@ -547,7 +551,7 @@ private void assignImplementations(HostedType type, Map<HostedType, ArrayList<Ho
* assignments into account.
*/
int slot = findSlot(method, vtablesMap, usedSlotsMap, vtablesSlots);
method.computedVTableIndex = slot;
installVTableIndex(method, slot);

/* Assign the vtable slot for the type and all subtypes. */
assignImplementations(method.getDeclaringClass(), method, slot, vtablesMap);
Expand All @@ -574,7 +578,6 @@ private void assignImplementations(HostedType type, HostedMethod method, int slo
assert vtable.get(slot) == null;
vtable.set(slot, resolvedMethod);
}
resolvedMethod.computedVTableIndex = slot;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@
import com.oracle.svm.core.config.ConfigurationValues;
import com.oracle.svm.core.graal.meta.KnownOffsets;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.hub.DynamicHubTypeCheckUtil;
import com.oracle.svm.core.hub.DynamicHubTypeCheckUtil.TypeCheckData;
import com.oracle.svm.core.hub.DynamicHubUtils;
import com.oracle.svm.core.hub.DynamicHubUtils.TypeCheckData;
import com.oracle.svm.core.hub.LayoutEncoding;
import com.oracle.svm.core.hub.RuntimeClassLoading.ClassDefinitionInfo;
import com.oracle.svm.core.hub.RuntimeDynamicHubMetadata;
Expand Down Expand Up @@ -306,7 +306,7 @@ public DynamicHub createHub(ParserKlass parsed, ClassDefinitionInfo info, int ty
}

/* Compute type check data, which might be based on interface hashing. */
DynamicHubTypeCheckUtil.TypeCheckData typeCheckData = computeTypeCheckData(typeID, isInterface, numClassTypes, numInterfacesTypes, superHub, dispatchTable, transitiveSuperInterfaces);
DynamicHubUtils.TypeCheckData typeCheckData = computeTypeCheckData(typeID, isInterface, numClassTypes, numInterfacesTypes, superHub, dispatchTable, transitiveSuperInterfaces);

int[] openTypeWorldTypeCheckSlots = typeCheckData.openTypeWorldTypeCheckSlots();
int[] openTypeWorldInterfaceHashTable = typeCheckData.openTypeWorldInterfaceHashTable();
Expand Down Expand Up @@ -464,7 +464,7 @@ private static TypeCheckData computeTypeCheckData(int typeID, boolean typeIsInte
long vTableBaseOffset = KnownOffsets.singleton().getVTableBaseOffset();
long vTableEntrySize = KnownOffsets.singleton().getVTableEntrySize();

return DynamicHubTypeCheckUtil.computeOpenTypeWorldTypeCheckData(!typeIsInterface, typeHierarchy, interfaceIDs, iTableStartingIndices, vTableBaseOffset, vTableEntrySize);
return DynamicHubUtils.computeOpenTypeWorldTypeCheckData(!typeIsInterface, typeHierarchy, interfaceIDs, iTableStartingIndices, vTableBaseOffset, vTableEntrySize);
}

private static void fillVTable(DynamicHub hub, InterpreterResolvedJavaMethod[] vtable) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.oracle.svm.core.graal.meta.KnownOffsets;
import com.oracle.svm.core.graal.snippets.OpenTypeWorldDispatchTableSnippets;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.hub.DynamicHubUtils;
import com.oracle.svm.core.hub.RuntimeClassLoading;
import com.oracle.svm.core.jdk.InternalVMMethod;
import com.oracle.svm.core.meta.MethodRef;
Expand Down Expand Up @@ -677,23 +678,11 @@ public static void ensureClassInitialized(Class<?> clazz) throws SemanticJavaExc
}
}

static CFunctionPointer peekAtSVMVTable(Class<?> seedClass, Class<?> thisClass, int vTableIndex, boolean isInvokeInterface) {
DynamicHub seedHub = DynamicHub.fromClass(seedClass);
static CFunctionPointer peekAtSVMVTable(Class<?> callTargetClass, Class<?> thisClass, int vTableIndex, boolean isInvokeInterface) {
DynamicHub callTargetHub = DynamicHub.fromClass(callTargetClass);
DynamicHub thisHub = DynamicHub.fromClass(thisClass);

int vtableOffset = KnownOffsets.singleton().getVTableOffset(vTableIndex, false);

if (SubstrateOptions.useClosedTypeWorldHubLayout()) {
vtableOffset += KnownOffsets.singleton().getVTableBaseOffset();
} else {
VMError.guarantee(seedHub.isInterface() == isInvokeInterface);

if (!seedHub.isInterface()) {
vtableOffset += KnownOffsets.singleton().getVTableBaseOffset();
} else {
vtableOffset += (int) OpenTypeWorldDispatchTableSnippets.determineITableStartingOffset(thisHub, seedHub.getInterfaceID());
}
}
VMError.guarantee(callTargetHub.isInterface() == isInvokeInterface);
int vtableOffset = DynamicHubUtils.determineDispatchTableOffset(thisHub, callTargetHub, vTableIndex);
MethodRef vtableEntry = Word.objectToTrackedPointer(thisHub).readWord(vtableOffset);
return getSVMVTableCodePointer(vtableEntry);
}
Expand Down Expand Up @@ -722,20 +711,16 @@ private static InterpreterResolvedJavaMethod peekAtInterpreterVTable(Class<?> se
VMError.guarantee(vTable != null);

DynamicHub seedHub = DynamicHub.fromClass(seedClass);
VMError.guarantee(isInvokeInterface == seedHub.isInterface());

if (SubstrateOptions.useClosedTypeWorldHubLayout()) {
VMError.guarantee(vTableIndex > 0 && vTableIndex < vTable.length);
return vTable[vTableIndex];
int idx;
if (SubstrateOptions.useClosedTypeWorldHubLayout() || !seedHub.isInterface()) {
idx = vTableIndex;
} else {
VMError.guarantee(seedHub.isInterface() == isInvokeInterface);

if (!seedHub.isInterface()) {
return vTable[vTableIndex];
} else {
int iTableStartingIndex = determineITableStartingIndex(DynamicHub.fromClass(thisClass), seedHub.getInterfaceID());
return vTable[iTableStartingIndex + vTableIndex];
}
idx = vTableIndex + determineITableStartingIndex(DynamicHub.fromClass(thisClass), seedHub.getInterfaceID());
}
VMError.guarantee(idx >= 0 && idx < vTable.length);
return vTable[idx];
}

private static int determineITableStartingIndex(DynamicHub thisHub, int interfaceID) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1920,7 +1920,8 @@ static Result fromThrowable(Throwable throwable) {

static Result ofInvoke(boolean isVirtual, InterpreterResolvedJavaMethod method, Object... args) {
try {
return fromValue(InterpreterToVM.dispatchInvocation(method, args, isVirtual, false, false, false, false));
boolean isInvokeInterface = method.getDeclaringClass().isInterface();
return fromValue(InterpreterToVM.dispatchInvocation(method, args, isVirtual, false, false, isInvokeInterface, false));
} catch (SemanticJavaException e) {
return fromThrowable(e.getCause());
} catch (StackOverflowError | OutOfMemoryError error) {
Expand Down