Skip to content
Permalink
Browse files
8262011: [JVMCI] allow printing to tty from unattached libgraal thread
Reviewed-by: kvn, never
  • Loading branch information
Doug Simon committed Feb 23, 2021
1 parent 0257caa commit d2b9c227e55defc37c0b0f6362637823ced6a220
@@ -216,7 +216,9 @@ void JVMCI::vlog(int level, const char* format, va_list ap) {
StringEventLog* events = level == 1 ? _events : _verbose_events;
guarantee(events != NULL, "JVMCI event log not yet initialized");
Thread* thread = Thread::current_or_null_safe();
events->logv(thread, format, ap);
if (thread != NULL) {
events->logv(thread, format, ap);
}
}
}

@@ -1575,91 +1575,22 @@ C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv* env, jobject, jobject _hs_
HotSpotJVMCI::HotSpotStackFrameReference::set_objectsMaterialized(JVMCIENV, hs_frame, JNI_TRUE);
C2V_END

// Creates a scope where the current thread is attached and detached
// from HotSpot if it wasn't already attached when entering the scope.
extern "C" int jio_printf(const char *fmt, ...);
class AttachDetach : public StackObj {
public:
bool _attached;
AttachDetach(JNIEnv* env, JavaThread* current_thread) {
if (current_thread == NULL) {
extern struct JavaVM_ main_vm;
JNIEnv* hotspotEnv;
jint res = main_vm.AttachCurrentThread((void**)&hotspotEnv, NULL);
_attached = res == JNI_OK;
static volatile int report_attach_error = 0;
if (res != JNI_OK && report_attach_error == 0 && Atomic::cmpxchg(&report_attach_error, 0, 1) == 0) {
// Only report an attach error once
jio_printf("Warning: attaching current thread to VM failed with %d (future attach errors are suppressed)\n", res);
}
} else {
_attached = false;
}
}
~AttachDetach() {
if (_attached && get_current_thread() != NULL) {
extern struct JavaVM_ main_vm;
jint res = main_vm.DetachCurrentThread();
static volatile int report_detach_error = 0;
if (res != JNI_OK && report_detach_error == 0 && Atomic::cmpxchg(&report_detach_error, 0, 1) == 0) {
// Only report an attach error once
jio_printf("Warning: detaching current thread from VM failed with %d (future attach errors are suppressed)\n", res);
}
}
}
};

C2V_VMENTRY_PREFIX(jint, writeDebugOutput, (JNIEnv* env, jobject, jbyteArray bytes, jint offset, jint length, bool flush, bool can_throw))
AttachDetach ad(env, thread);
bool use_tty = true;
if (thread == NULL) {
if (!ad._attached) {
// Can only use tty if the current thread is attached
JVMCI_event_1("Cannot write to tty on unattached thread");
return 0;
}
thread = get_current_thread();
}
JVMCITraceMark jtm("writeDebugOutput");
C2V_BLOCK(void, writeDebugOutput, (JNIEnv* env, jobject, jbyteArray bytes, jint offset, jint length))
if (bytes == NULL) {
if (can_throw) {
JVMCI_THROW_0(NullPointerException);
}
return -1;
}
JVMCIPrimitiveArray array = JVMCIENV->wrap(bytes);

// Check if offset and length are non negative.
if (offset < 0 || length < 0) {
if (can_throw) {
JVMCI_THROW_0(ArrayIndexOutOfBoundsException);
}
return -2;
}
// Check if the range is valid.
int array_length = JVMCIENV->get_length(array);
if ((((unsigned int) length + (unsigned int) offset) > (unsigned int) array_length)) {
if (can_throw) {
JVMCI_THROW_0(ArrayIndexOutOfBoundsException);
}
return -2;
}
jbyte buffer[O_BUFLEN];
while (length > 0) {
int copy_len = MIN2(length, (jint)O_BUFLEN);
JVMCIENV->copy_bytes_to(array, buffer, offset, copy_len);
tty->write((char*) buffer, copy_len);
length -= O_BUFLEN;
offset += O_BUFLEN;
// Use of tty does not require the current thread to be attached to the VM
// so no need for a full C2V_VMENTRY transition.
C2V_VMENTRY_PREFIX(void, writeDebugOutput, (JNIEnv* env, jobject, jlong buffer, jint length, bool flush))
if (length <= 8) {
tty->write((char*) &buffer, length);
} else {
tty->write((char*) buffer, length);
}
if (flush) {
tty->flush();
}
return 0;
C2V_END

C2V_VMENTRY(void, flushDebugOutput, (JNIEnv* env, jobject))
// Use of tty does not require the current thread to be attached to the VM
// so no need for a full C2V_VMENTRY transition.
C2V_VMENTRY_PREFIX(void, flushDebugOutput, (JNIEnv* env, jobject))
tty->flush();
C2V_END

@@ -2793,7 +2724,7 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "iterateFrames", CC "([" RESOLVED_METHOD "[" RESOLVED_METHOD "I" INSPECTED_FRAME_VISITOR ")" OBJECT, FN_PTR(iterateFrames)},
{CC "materializeVirtualObjects", CC "(" HS_STACK_FRAME_REF "Z)V", FN_PTR(materializeVirtualObjects)},
{CC "shouldDebugNonSafepoints", CC "()Z", FN_PTR(shouldDebugNonSafepoints)},
{CC "writeDebugOutput", CC "([BIIZZ)I", FN_PTR(writeDebugOutput)},
{CC "writeDebugOutput", CC "(JIZ)V", FN_PTR(writeDebugOutput)},
{CC "flushDebugOutput", CC "()V", FN_PTR(flushDebugOutput)},
{CC "methodDataProfileDataSize", CC "(JI)I", FN_PTR(methodDataProfileDataSize)},
{CC "getFingerprint", CC "(J)J", FN_PTR(getFingerprint)},
@@ -612,18 +612,14 @@ public static CompilerToVM compilerToVM() {
native boolean shouldDebugNonSafepoints();

/**
* Writes {@code length} bytes from {@code bytes} starting at offset {@code offset} to HotSpot's
* log stream.
* Writes {@code length} bytes from {@code buffer} to HotSpot's log stream.
*
* @param buffer if {@code length <= 8}, then the bytes are encoded in this value in native
* endianness order otherwise this is the address of a native memory buffer holding
* the bytes
* @param flush specifies if the log stream should be flushed after writing
* @param canThrow specifies if an error in the {@code bytes}, {@code offset} or {@code length}
* arguments should result in an exception or a negative return value
* @return 0 on success, -1 if {@code bytes == null && !canThrow}, -2 if {@code !canThrow} and
* copying would cause access of data outside array bounds
* @throws NullPointerException if {@code bytes == null}
* @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds
*/
native int writeDebugOutput(byte[] bytes, int offset, int length, boolean flush, boolean canThrow);
*/
native void writeDebugOutput(long buffer, int length, boolean flush);

/**
* Flush HotSpot's log stream.
@@ -35,6 +35,8 @@
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MethodHandle;
import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Formatter;
@@ -45,6 +47,7 @@
import java.util.ServiceLoader;
import java.util.function.Predicate;

import jdk.internal.misc.Unsafe;
import jdk.vm.ci.code.Architecture;
import jdk.vm.ci.code.CompilationRequest;
import jdk.vm.ci.code.CompilationRequestResult;
@@ -569,7 +572,7 @@ private HotSpotJVMCIRuntime() {
}

if (Option.PrintConfig.getBoolean()) {
configStore.printConfig();
configStore.printConfig(this);
}
}

@@ -884,7 +887,46 @@ void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledC
* @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds
*/
public int writeDebugOutput(byte[] bytes, int offset, int length, boolean flush, boolean canThrow) {
return compilerToVm.writeDebugOutput(bytes, offset, length, flush, canThrow);
return writeDebugOutput0(compilerToVm, bytes, offset, length, flush, canThrow);
}

/**
* @see #writeDebugOutput
*/
static int writeDebugOutput0(CompilerToVM vm, byte[] bytes, int offset, int length, boolean flush, boolean canThrow) {
if (bytes == null) {
if (!canThrow) {
return -1;
}
throw new NullPointerException();
}
if (offset < 0 || length < 0 || offset + length > bytes.length) {
if (!canThrow) {
return -2;
}
throw new ArrayIndexOutOfBoundsException();
}
if (length <= 8) {
ByteBuffer buffer = ByteBuffer.wrap(bytes, offset, length);
if (length != 8) {
ByteBuffer buffer8 = ByteBuffer.allocate(8);
buffer8.put(buffer);
buffer8.position(8);
buffer = buffer8;
}
buffer.order(ByteOrder.nativeOrder());
vm.writeDebugOutput(buffer.getLong(0), length, flush);
} else {
Unsafe unsafe = UnsafeAccess.UNSAFE;
long buffer = unsafe.allocateMemory(length);
try {
unsafe.copyMemory(bytes, vm.ARRAY_BYTE_BASE_OFFSET, null, buffer, length);
vm.writeDebugOutput(buffer, length, flush);
} finally {
unsafe.freeMemory(buffer);
}
}
return 0;
}

/**
@@ -902,7 +944,7 @@ public void write(byte[] b, int off, int len) throws IOException {
} else if (len == 0) {
return;
}
compilerToVm.writeDebugOutput(b, off, len, false, true);
writeDebugOutput(b, off, len, false, true);
}

@Override
@@ -1194,7 +1236,7 @@ public void exitHotSpot(int status) {
*/
JVMCIError exitHotSpotWithMessage(int status, String format, Object... args) {
byte[] messageBytes = String.format(format, args).getBytes();
compilerToVm.writeDebugOutput(messageBytes, 0, messageBytes.length, true, true);
writeDebugOutput(messageBytes, 0, messageBytes.length, true, true);
exitHotSpot(status);
throw JVMCIError.shouldNotReachHere();
}
@@ -477,7 +477,7 @@ public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR)
if (methodDataFilter != null && this.format("%H.%n").contains(methodDataFilter)) {
String line = methodData.toString() + System.lineSeparator();
byte[] lineBytes = line.getBytes();
CompilerToVM.compilerToVM().writeDebugOutput(lineBytes, 0, lineBytes.length, true, true);
HotSpotJVMCIRuntime.runtime().writeDebugOutput(lineBytes, 0, lineBytes.length, true, true);
}
}
}
@@ -161,39 +161,38 @@ public String toString() {
vmIntrinsics.size());
}

void printConfig() {
CompilerToVM vm = compilerToVm;
void printConfig(HotSpotJVMCIRuntime runtime) {
TreeMap<String, VMField> fields = new TreeMap<>(getFields());
for (VMField field : fields.values()) {
if (!field.isStatic()) {
printConfigLine(vm, "[vmconfig:instance field] %s %s {offset=%d[0x%x]}%n", field.type, field.name, field.offset, field.offset);
printConfigLine(runtime, "[vmconfig:instance field] %s %s {offset=%d[0x%x]}%n", field.type, field.name, field.offset, field.offset);
} else {
String value = field.value == null ? "null" : field.value instanceof Boolean ? field.value.toString() : String.format("%d[0x%x]", field.value, field.value);
printConfigLine(vm, "[vmconfig:static field] %s %s = %s {address=0x%x}%n", field.type, field.name, value, field.address);
printConfigLine(runtime, "[vmconfig:static field] %s %s = %s {address=0x%x}%n", field.type, field.name, value, field.address);
}
}
TreeMap<String, VMFlag> flags = new TreeMap<>(getFlags());
for (VMFlag flag : flags.values()) {
printConfigLine(vm, "[vmconfig:flag] %s %s = %s%n", flag.type, flag.name, flag.value);
printConfigLine(runtime, "[vmconfig:flag] %s %s = %s%n", flag.type, flag.name, flag.value);
}
TreeMap<String, Long> addresses = new TreeMap<>(getAddresses());
for (Map.Entry<String, Long> e : addresses.entrySet()) {
printConfigLine(vm, "[vmconfig:address] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue());
printConfigLine(runtime, "[vmconfig:address] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue());
}
TreeMap<String, Long> constants = new TreeMap<>(getConstants());
for (Map.Entry<String, Long> e : constants.entrySet()) {
printConfigLine(vm, "[vmconfig:constant] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue());
printConfigLine(runtime, "[vmconfig:constant] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue());
}
for (VMIntrinsicMethod e : getIntrinsics()) {
printConfigLine(vm, "[vmconfig:intrinsic] %d = %s.%s %s%n", e.id, e.declaringClass, e.name, e.descriptor);
printConfigLine(runtime, "[vmconfig:intrinsic] %d = %s.%s %s%n", e.id, e.declaringClass, e.name, e.descriptor);
}
}

@SuppressFBWarnings(value = "DM_DEFAULT_ENCODING", justification = "no localization here please!")
private static void printConfigLine(CompilerToVM vm, String format, Object... args) {
private static void printConfigLine(HotSpotJVMCIRuntime runtime, String format, Object... args) {
String line = String.format(format, args);
byte[] lineBytes = line.getBytes();
vm.writeDebugOutput(lineBytes, 0, lineBytes.length, true, true);
runtime.writeDebugOutput(lineBytes, 0, lineBytes.length, true, true);
}

}
@@ -295,10 +295,6 @@ public static boolean shouldDebugNonSafepoints() {
return CTVM.shouldDebugNonSafepoints();
}

public static void writeDebugOutput(byte[] bytes, int offset, int length) {
CTVM.writeDebugOutput(bytes, offset, length, true, true);
}

public static void flushDebugOutput() {
CTVM.flushDebugOutput();
}

1 comment on commit d2b9c22

@openjdk-notifier

This comment has been minimized.

Copy link

@openjdk-notifier openjdk-notifier bot commented on d2b9c22 Feb 23, 2021

Please sign in to comment.