Skip to content

Commit

Permalink
More optimized class initialization check in MethodHandle
Browse files Browse the repository at this point in the history
Check if a class has been initialized by calling a JITHelpers method
which can be optimized by the JIT.
Original implemenation uses Unsafe to load the class flag from J9Class
and JIT cannot see through it. With this change, JIT is able to
eliminate the check if it knows what the class is and that the class
has been initialized.
This change also caches the JITHelpers object and the Unsafe object in
MethodHandle as a static field so that when a JITHelpers call is
reduced, the load of JITHelpers object can also be reduced.

Signed-off-by: Liqun Liu <[email protected]>
  • Loading branch information
Liqun Liu committed Oct 17, 2017
1 parent f50d159 commit 6960b3a
Show file tree
Hide file tree
Showing 20 changed files with 181 additions and 96 deletions.
24 changes: 24 additions & 0 deletions jcl/src/java.base/share/classes/com/ibm/jit/JITHelpers.java
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,30 @@ public Object optimizedClone(Object srcObj) throws CloneNotSupportedException {
return clnObj;
}

/**
* Get class initialize status flag. Calls to this method will be recognized and optimized by the JIT.
* @parm defc
* The class whose initialize status is desired.
* @return
* initializeStatus from J9Class.
*/
public final int getClassInitializeStatus(Class<?> defc) {
long defcClass = 0;
if (is32Bit()) {
defcClass = getJ9ClassFromClass32(defc);
} else {
defcClass = getJ9ClassFromClass64(defc);
}
int initStatus = 0;
if (4 == VM.ADDRESS_SIZE) {
initStatus = unsafe.getInt(defcClass + VM.J9CLASS_INITIALIZE_STATUS_OFFSET);
} else {
initStatus = (int)unsafe.getLong(defcClass + VM.J9CLASS_INITIALIZE_STATUS_OFFSET);
}
return initStatus;
}


/**
* Determines whether the underlying platform's memory model is little-endian.
*
Expand Down
3 changes: 3 additions & 0 deletions jcl/src/java.base/share/classes/com/ibm/oti/vm/VM.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ public final class VM {

public static final int J9_ACC_CLASS_INTERNAL_PRIMITIVE_TYPE;

public static final int J9CLASS_INIT_SUCCEEDED;

/* Valid types for J9_JIT_STRING_DEDUP_POLICY are:
* - J9_JIT_STRING_DEDUP_POLICY_DISABLED
* - J9_JIT_STRING_DEDUP_POLICY_FAVOUR_HIGHER
Expand Down Expand Up @@ -161,6 +163,7 @@ public final class VM {

J9_ACC_CLASS_INTERNAL_PRIMITIVE_TYPE = 0;
J9_ACC_CLASS_ARRAY = 0;
J9CLASS_INIT_SUCCEEDED = 0;

J9_JIT_STRING_DEDUP_POLICY = 0;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*[INCLUDE-IF Sidecar17]*/
/*******************************************************************************
* Copyright (c) 2009, 2009 IBM Corp. and others
* Copyright (c) 2009, 2017 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -56,41 +56,41 @@ private final static MethodType fieldMethodType(Class<?> returnType, Class<?> ar
@FrameIteratorSkip
private final int invokeExact_thunkArchetype_I(Object receiver, int argPlaceholder) {
if (Modifier.isVolatile(final_modifiers))
return getUnsafe().getIntVolatile(receiver, vmSlot+HEADER_SIZE);
return UNSAFE.getIntVolatile(receiver, vmSlot + HEADER_SIZE);
else
return getUnsafe().getInt (receiver, vmSlot+HEADER_SIZE);
return UNSAFE.getInt (receiver, vmSlot + HEADER_SIZE);
}

@FrameIteratorSkip
private final long invokeExact_thunkArchetype_J(Object receiver, int argPlaceholder) {
if (Modifier.isVolatile(final_modifiers))
return getUnsafe().getLongVolatile(receiver, vmSlot+HEADER_SIZE);
return UNSAFE.getLongVolatile(receiver, vmSlot + HEADER_SIZE);
else
return getUnsafe().getLong (receiver, vmSlot+HEADER_SIZE);
return UNSAFE.getLong (receiver, vmSlot + HEADER_SIZE);
}

@FrameIteratorSkip
private final float invokeExact_thunkArchetype_F(Object receiver, int argPlaceholder) {
if (Modifier.isVolatile(final_modifiers))
return getUnsafe().getFloatVolatile(receiver, vmSlot+HEADER_SIZE);
return UNSAFE.getFloatVolatile(receiver, vmSlot + HEADER_SIZE);
else
return getUnsafe().getFloat (receiver, vmSlot+HEADER_SIZE);
return UNSAFE.getFloat (receiver, vmSlot + HEADER_SIZE);
}

@FrameIteratorSkip
private final double invokeExact_thunkArchetype_D(Object receiver, int argPlaceholder) {
if (Modifier.isVolatile(final_modifiers))
return getUnsafe().getDoubleVolatile(receiver, vmSlot+HEADER_SIZE);
return UNSAFE.getDoubleVolatile(receiver, vmSlot + HEADER_SIZE);
else
return getUnsafe().getDouble (receiver, vmSlot+HEADER_SIZE);
return UNSAFE.getDouble (receiver, vmSlot + HEADER_SIZE);
}

@FrameIteratorSkip
private final Object invokeExact_thunkArchetype_L(Object receiver, int argPlaceholder) {
if (Modifier.isVolatile(final_modifiers))
return getUnsafe().getObjectVolatile(receiver, vmSlot+HEADER_SIZE);
return UNSAFE.getObjectVolatile(receiver, vmSlot + HEADER_SIZE);
else
return getUnsafe().getObject (receiver, vmSlot+HEADER_SIZE);
return UNSAFE.getObject (receiver, vmSlot + HEADER_SIZE);
}

private static final ThunkTable _thunkTable = new ThunkTable();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*[INCLUDE-IF Sidecar17]*/
/*******************************************************************************
* Copyright (c) 2009, 2009 IBM Corp. and others
* Copyright (c) 2009, 2017 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -58,41 +58,41 @@ private final static MethodType fieldMethodType(Class<?> referenceClass, Class<?
@FrameIteratorSkip
private final void invokeExact_thunkArchetype_V(Object receiver, int newValue, int argPlaceholder) {
if (Modifier.isVolatile(final_modifiers))
getUnsafe().putIntVolatile(receiver, vmSlot+HEADER_SIZE, newValue);
UNSAFE.putIntVolatile(receiver, vmSlot + HEADER_SIZE, newValue);
else
getUnsafe().putInt (receiver, vmSlot+HEADER_SIZE, newValue);
UNSAFE.putInt (receiver, vmSlot + HEADER_SIZE, newValue);
}

@FrameIteratorSkip
private final void invokeExact_thunkArchetype_V(Object receiver, long newValue, int argPlaceholder) {
if (Modifier.isVolatile(final_modifiers))
getUnsafe().putLongVolatile(receiver, vmSlot+HEADER_SIZE, newValue);
UNSAFE.putLongVolatile(receiver, vmSlot + HEADER_SIZE, newValue);
else
getUnsafe().putLong (receiver, vmSlot+HEADER_SIZE, newValue);
UNSAFE.putLong (receiver, vmSlot + HEADER_SIZE, newValue);
}

@FrameIteratorSkip
private final void invokeExact_thunkArchetype_V(Object receiver, float newValue, int argPlaceholder) {
if (Modifier.isVolatile(final_modifiers))
getUnsafe().putFloatVolatile(receiver, vmSlot+HEADER_SIZE, newValue);
UNSAFE.putFloatVolatile(receiver, vmSlot + HEADER_SIZE, newValue);
else
getUnsafe().putFloat (receiver, vmSlot+HEADER_SIZE, newValue);
UNSAFE.putFloat (receiver, vmSlot + HEADER_SIZE, newValue);
}

@FrameIteratorSkip
private final void invokeExact_thunkArchetype_V(Object receiver, double newValue, int argPlaceholder) {
if (Modifier.isVolatile(final_modifiers))
getUnsafe().putDoubleVolatile(receiver, vmSlot+HEADER_SIZE, newValue);
UNSAFE.putDoubleVolatile(receiver, vmSlot + HEADER_SIZE, newValue);
else
getUnsafe().putDouble (receiver, vmSlot+HEADER_SIZE, newValue);
UNSAFE.putDouble (receiver, vmSlot + HEADER_SIZE, newValue);
}

@FrameIteratorSkip
private final void invokeExact_thunkArchetype_V(Object receiver, Object newValue, int argPlaceholder) {
if (Modifier.isVolatile(final_modifiers))
getUnsafe().putObjectVolatile(receiver, vmSlot+HEADER_SIZE, newValue);
UNSAFE.putObjectVolatile(receiver, vmSlot + HEADER_SIZE, newValue);
else
getUnsafe().putObject (receiver, vmSlot+HEADER_SIZE, newValue);
UNSAFE.putObject (receiver, vmSlot + HEADER_SIZE, newValue);
}

private static final ThunkTable _thunkTable = new ThunkTable();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*[INCLUDE-IF Sidecar17]*/
/*******************************************************************************
* Copyright (c) 2009, 2009 IBM Corp. and others
* Copyright (c) 2009, 2017 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -47,9 +47,9 @@ protected final long jittedMethodAddress(Object receiver) {
long receiverClass = getJ9ClassFromClass(receiver.getClass());
long result;
if (VTABLE_ENTRY_SIZE == 4) {
result = getUnsafe().getInt(receiverClass - vtableOffset(receiver));
result = UNSAFE.getInt(receiverClass - vtableOffset(receiver));
} else {
result = getUnsafe().getLong(receiverClass - vtableOffset(receiver));
result = UNSAFE.getLong(receiverClass - vtableOffset(receiver));
}
return result;
}
Expand Down
39 changes: 11 additions & 28 deletions jcl/src/java.base/share/classes/java/lang/invoke/MethodHandle.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,22 +128,10 @@ public abstract class MethodHandle {

static final int PUBLIC_FINAL_NATIVE = Modifier.PUBLIC | Modifier.FINAL | Modifier.NATIVE | 0x1000 /* Synthetic */;

private static final class UnsafeGetter {
public static final Unsafe myUnsafe = Unsafe.getUnsafe();
}
static final Unsafe UNSAFE = Unsafe.getUnsafe();

static final Unsafe getUnsafe() {
return UnsafeGetter.myUnsafe;
}

private static final class JITHelpersGetter {
public static final JITHelpers myJITHelpers = JITHelpers.getHelpers();
}
static final JITHelpers JITHELPERS = JITHelpers.getHelpers();

static final JITHelpers getJITHelpers() {
return JITHelpersGetter.myJITHelpers;
}

private static final int CUSTOM_THUNK_INVOCATION_COUNT = 1000;
private static final int DONT_CHECK_FOR_A_WHILE_COUNT = -1000000000;

Expand Down Expand Up @@ -228,11 +216,10 @@ ThunkTuple computeThunks(Object arg) {
}

static long getJ9ClassFromClass(Class<?> c) {
JITHelpers h = getJITHelpers();
if (h.is32Bit()) {
return h.getJ9ClassFromClass32(c);
if (JITHELPERS.is32Bit()) {
return JITHELPERS.getJ9ClassFromClass32(c);
} else {
return h.getJ9ClassFromClass64(c);
return JITHELPERS.getJ9ClassFromClass64(c);
}
}

Expand Down Expand Up @@ -273,8 +260,6 @@ MethodHandle cloneWithNewType(MethodType newType) {
enforceArityLimit(kind, this.type);
/* Must be called even laster as it uses the method type */
this.thunks = computeThunks(thunkArg);
/* Touch JITHelpers to make sure CP entries are resolved when needed later */
getJ9ClassFromClass(MethodHandle.class);
}

MethodHandle(MethodHandle original, MethodType newType) {
Expand Down Expand Up @@ -837,19 +822,17 @@ MethodHandle insertArguments(MethodHandle equivalent, MethodHandle unboxingHandl

@SuppressWarnings("unused")
private static final MethodHandle resolveInvokeDynamic(long j9class, String name, String methodDescriptor, long bsmData) throws Throwable {
Unsafe unsafe = getUnsafe();
MethodHandle result = null;
MethodType type = null;

try {
VMLangAccess access = VM.getVMLangAccess();
Object internalRamClass = access.createInternalRamClass(j9class);
JITHelpers jitHelper = getJITHelpers();
Class<?> classObject = null;
if (jitHelper.is32Bit()) {
classObject = jitHelper.getClassFromJ9Class32((int)j9class);
if (JITHELPERS.is32Bit()) {
classObject = JITHELPERS.getClassFromJ9Class32((int)j9class);
} else {
classObject = jitHelper.getClassFromJ9Class64(j9class);
classObject = JITHELPERS.getClassFromJ9Class64(j9class);
}

Objects.requireNonNull(classObject);
Expand All @@ -859,8 +842,8 @@ private static final MethodHandle resolveInvokeDynamic(long j9class, String name
} catch (TypeNotPresentException e) {
throw throwNoClassDefFoundError(e);
}
int bsmIndex = unsafe.getShort(bsmData);
int bsmArgCount = unsafe.getShort(bsmData + BSM_ARGUMENT_COUNT_OFFSET);
int bsmIndex = UNSAFE.getShort(bsmData);
int bsmArgCount = UNSAFE.getShort(bsmData + BSM_ARGUMENT_COUNT_OFFSET);
long bsmArgs = bsmData + BSM_ARGUMENTS_OFFSET;
MethodHandle bsm = getCPMethodHandleAt(internalRamClass, bsmIndex);
if (null == bsm) {
Expand Down Expand Up @@ -889,7 +872,7 @@ private static final MethodHandle resolveInvokeDynamic(long j9class, String name

for (int i = 0; i < bsmArgCount; i++) {
int staticArgIndex = BSM_OPTIONAL_ARGUMENTS_START_INDEX + i;
short index = unsafe.getShort(bsmArgs + (i * BSM_ARGUMENT_SIZE));
short index = UNSAFE.getShort(bsmArgs + (i * BSM_ARGUMENT_SIZE));
int cpType = getCPTypeAt(internalRamClass, index);
Object cpEntry = null;
switch (cpType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public class MutableCallSite extends CallSite {
private static final long targetFieldOffset = initializeTargetFieldOffset();
private static long initializeTargetFieldOffset(){
try{
return MethodHandle.getUnsafe().objectFieldOffset(MutableCallSite.class.getDeclaredField("target")); //$NON-NLS-1$
return MethodHandle.UNSAFE.objectFieldOffset(MutableCallSite.class.getDeclaredField("target")); //$NON-NLS-1$
} catch (Exception e) {
InternalError ie = new InternalError();
ie.initCause(e);
Expand Down Expand Up @@ -119,7 +119,7 @@ public final MethodHandle getTarget() {
private static final Object bypassBase = initializeBypassBase();
private static Object initializeBypassBase() {
try{
return MethodHandle.getUnsafe().staticFieldBase(MutableCallSite.class.getDeclaredField("targetFieldOffset")); //$NON-NLS-1$
return MethodHandle.UNSAFE.staticFieldBase(MutableCallSite.class.getDeclaredField("targetFieldOffset")); //$NON-NLS-1$
} catch (Exception e) {
InternalError ie = new InternalError();
ie.initCause(e);
Expand Down Expand Up @@ -160,9 +160,9 @@ public void setTarget(MethodHandle newTarget) {
// Equivalence check saved us a thaw, so it's worth doing them every time.
equivalenceInterval = 1;
/*[IF Sidecar19-SE-B174]*/
MethodHandle.getUnsafe().compareAndSetObject(this, targetFieldOffset, oldTarget, newTarget);
MethodHandle.UNSAFE.compareAndSetObject(this, targetFieldOffset, oldTarget, newTarget);
/*[ELSE]
MethodHandle.getUnsafe().compareAndSwapObject(this, targetFieldOffset, oldTarget, newTarget);
MethodHandle.UNSAFE.compareAndSwapObject(this, targetFieldOffset, oldTarget, newTarget);
/*[ENDIF]*/
} else {
thaw(oldTarget, newTarget);
Expand All @@ -175,7 +175,7 @@ public void setTarget(MethodHandle newTarget) {
thaw(oldTarget, newTarget);
}
if (globalRefCleaner.bypassOffset != 0) {
MethodHandle.getUnsafe().putObject(bypassBase, globalRefCleaner.bypassOffset, newTarget);
MethodHandle.UNSAFE.putObject(bypassBase, globalRefCleaner.bypassOffset, newTarget);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*[INCLUDE-IF Sidecar17]*/
/*******************************************************************************
* Copyright (c) 2010, 2010 IBM Corp. and others
* Copyright (c) 2010, 2017 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand All @@ -26,12 +26,8 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/*[IF Sidecar19-SE]
import jdk.internal.misc.Unsafe;
/*[ELSE]*/
import sun.misc.Unsafe;
/*[ENDIF]*/
import com.ibm.oti.vm.VM;
import com.ibm.jit.JITHelpers;

/**
* PrimitiveHandle is a subclass of MethodHandle used for grouping MethodHandles that directly refer a Java-level method.
Expand Down Expand Up @@ -170,16 +166,8 @@ int getModifiers() {

final void initializeClassIfRequired() {
if (Modifier.isStatic(this.rawModifiers)) {
long defcClass = getJ9ClassFromClass(defc);
Unsafe unsafe = getUnsafe();
int initStatus = 0;
if (4 == VM.ADDRESS_SIZE) {
initStatus = unsafe.getInt(defcClass + com.ibm.oti.vm.VM.J9CLASS_INITIALIZE_STATUS_OFFSET);
} else {
initStatus = (int)unsafe.getLong(defcClass + com.ibm.oti.vm.VM.J9CLASS_INITIALIZE_STATUS_OFFSET);
}
if (initStatus != 1) {
unsafe.ensureClassInitialized(defc);
if (JITHELPERS.getClassInitializeStatus(defc) != VM.J9CLASS_INIT_SUCCEEDED) {
UNSAFE.ensureClassInitialized(defc);
}
}
}
Expand Down
Loading

0 comments on commit 6960b3a

Please sign in to comment.