Skip to content

Commit

Permalink
Trace class initialization and object instantiation using a JVMTI agent.
Browse files Browse the repository at this point in the history
  • Loading branch information
Aleksandar Gradinac committed Aug 24, 2020
1 parent e666b90 commit 8c210f7
Show file tree
Hide file tree
Showing 27 changed files with 1,075 additions and 287 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -54,7 +54,7 @@ public interface RuntimeClassInitializationSupport {

void initializeAtBuildTime(Class<?> aClass, String reason);

void reportClassInitialized(Class<?> aClass);
void reportClassInitialized(Class<?> aClass, StackTraceElement[] stackTrace);

void reportObjectInstantiated(Object o);
void reportObjectInstantiated(Object o, StackTraceElement[] stackTrace);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -67,21 +67,21 @@ public class ClassInitializationTracking {
* This method is called from the instrumented class initialization methods.
*/
@SuppressWarnings({"unused", "ConstantConditions"})
public static void reportClassInitialized(Class<?> c) {
public static void reportClassInitialized(Class<?> c, StackTraceElement[] stackTrace) {
if (ImageSingletonsSupport.isInstalled() && ImageSingletons.contains(RuntimeClassInitializationSupport.class)) {
RuntimeClassInitializationSupport runtimeClassInitialization = ImageSingletons.lookup(RuntimeClassInitializationSupport.class);
runtimeClassInitialization.reportClassInitialized(c);
runtimeClassInitialization.reportClassInitialized(c, stackTrace);
}
}

/**
* This method is called from the instrumented class initialization methods.
*/
@SuppressWarnings({"unused"})
public static void reportObjectInstantiated(Object o) {
public static void reportObjectInstantiated(Object o, StackTraceElement[] stackTrace) {
if (ImageSingletonsSupport.isInstalled() && ImageSingletons.contains(RuntimeClassInitializationSupport.class)) {
RuntimeClassInitializationSupport runtimeClassInitialization = ImageSingletons.lookup(RuntimeClassInitializationSupport.class);
runtimeClassInitialization.reportObjectInstantiated(o);
runtimeClassInitialization.reportObjectInstantiated(o, stackTrace);
}
}

Expand Down
16 changes: 13 additions & 3 deletions substratevm/mx.substratevm/mx_substratevm.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#
# ----------------------------------------------------------------------------------------------------
#
# Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -293,7 +293,7 @@ def run_musl_basic_tests():
def native_image_context(common_args=None, hosted_assertions=True, native_image_cmd='', config=None, build_if_missing=False):
config = config or graalvm_config()
common_args = [] if common_args is None else common_args
base_args = ['--no-fallback', '-H:+EnforceMaxRuntimeCompileMethods', '-H:+TraceClassInitialization']
base_args = ['--no-fallback', '-H:+EnforceMaxRuntimeCompileMethods']
base_args += ['-H:Path=' + svmbuild_dir()]
has_server = mx.get_os() != 'windows'
if mx.get_opts().verbose:
Expand Down Expand Up @@ -862,6 +862,17 @@ def _native_image_launcher_extra_jvm_args():
'--features=com.oracle.svm.agent.NativeImageAgent$RegistrationFeature'
],
),
mx_sdk_vm.LibraryConfig(
destination="<lib:native-image-diagnostics-agent>",
jvm_library=True,
jar_distributions=[
'substratevm:JVMTI_AGENT_BASE',
'substratevm:SVM_DIAGNOSTICS_AGENT',
],
build_args=[
'--features=com.oracle.svm.diagnosticsagent.NativeImageDiagnosticsAgent$RegistrationFeature',
],
),
],
provided_executables=['bin/<cmd:rebuild-images>'],
installable=True,
Expand Down Expand Up @@ -1081,7 +1092,6 @@ def build_and_test_clinittest_image(native_image, args=None):
native_image(
['-H:Path=' + build_dir, '-cp', test_cp, '-H:Class=com.oracle.svm.test.TestClassInitializationMustBeSafe',
'-H:Features=com.oracle.svm.test.TestClassInitializationMustBeSafeFeature',
'-H:+TraceClassInitialization',
'-H:+PrintClassInitialization', '-H:Name=clinittest', '-H:+ReportExceptionStackTraces'] + args)
mx.run([join(build_dir, 'clinittest')])

Expand Down
1 change: 0 additions & 1 deletion substratevm/mx.substratevm/mx_substratevm_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ def list_jars(path):
'-Dnative-image.benchmark.extra-image-build-argument=-H:-ThrowUnsafeOffsetErrors'],
'finagle-http' : ['-Dnative-image.benchmark.extra-image-build-argument=--initialize-at-build-time=com.fasterxml.jackson.annotation.JsonProperty$Access', '-Dnative-image.benchmark.extra-image-build-argument=--allow-incomplete-classpath'],
'log-regression' : ['-Dnative-image.benchmark.extra-image-build-argument=--allow-incomplete-classpath',
'-Dnative-image.benchmark.extra-image-build-argument=-H:+TraceClassInitialization',
'-Dnative-image.benchmark.extra-image-build-argument=-H:IncludeResourceBundles=sun.security.util.Resources,javax.servlet.http.LocalStrings,javax.servlet.LocalStrings',
'-Dnative-image.benchmark.extra-image-build-argument=--report-unsupported-elements-at-runtime',
'-Dnative-image.benchmark.extra-image-build-argument=-H:-ThrowUnsafeOffsetErrors',
Expand Down
30 changes: 30 additions & 0 deletions substratevm/mx.substratevm/suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,24 @@
"spotbugs": "false",
},

"com.oracle.svm.diagnosticsagent": {
"subDir": "src",
"sourceDirs": [
"src",
"resources"
],
"dependencies": [
"JVMTI_AGENT_BASE",
],
"checkstyle": "com.oracle.svm.driver",
"workingSets": "SVM",
"annotationProcessors": [
"compiler:GRAAL_PROCESSOR",
],
"javaCompliance": "8+",
"spotbugs": "false",
},

"com.oracle.svm.truffle.tck" : {
"subDir": "src",
"sourceDirs": ["src"],
Expand Down Expand Up @@ -1063,6 +1081,18 @@
# vm: included as binary, tool descriptor intentionally not copied
},

"SVM_DIAGNOSTICS_AGENT": {
"subDir": "src",
"description" : "Native-image diagnostics agent",
"dependencies": [
"com.oracle.svm.diagnosticsagent",
],
"distDependencies": [
"JVMTI_AGENT_BASE",
"LIBRARY_SUPPORT",
],
},

"SVM_CONFIGURE": {
"subDir": "src",
"description" : "SubstrateVM native-image configuration tool",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,7 @@ private static boolean loadClass(JNIEnvironment jni, Breakpoint bp) {
JNIObjectHandle callerClass = nullHandle();
JvmtiFrameInfo frameInfo = StackValue.get(JvmtiFrameInfo.class);
CIntPointer frameCountPtr = StackValue.get(CIntPointer.class);
if (jvmtiFunctions().GetStackTrace().invoke(jvmtiEnv(), nullHandle(), 1, 1, frameInfo, frameCountPtr) == JvmtiError.JVMTI_ERROR_NONE && frameCountPtr.read() == 1) {
if (jvmtiFunctions().GetStackTrace().invoke(jvmtiEnv(), nullHandle(), 1, 1, (WordPointer) frameInfo, frameCountPtr) == JvmtiError.JVMTI_ERROR_NONE && frameCountPtr.read() == 1) {
callerClass = getMethodDeclaringClass(frameInfo.getMethod());
if (callerClass.notEqual(nullHandle()) && jniFunctions().getIsAssignableFrom().invoke(jni, callerClass, agent.handles().javaLangClassLoader)) {
// ignore recursive class loader calls, we must have seen the root invocation
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -251,8 +251,13 @@ public Boolean getValue(OptionValues values) {
@Option(help = "Trace VMOperation execution.")//
public static final HostedOptionKey<Boolean> TraceVMOperations = new HostedOptionKey<>(false);

@Option(help = "Instrument code to trace and report class initialization.")//
public static final HostedOptionKey<Boolean> TraceClassInitialization = new HostedOptionKey<>(false);
@APIOption(name = "trace-class-initialization")//
@Option(help = "Comma-separated list of fully qualified class names that class initialization is traced for.")//
public static final HostedOptionKey<String> TraceClassInitialization = new HostedOptionKey<>("");

@APIOption(name = "trace-object-instantiation")//
@Option(help = "Comma-separated list of fully qualified class names that object instantiation is traced for.")//
public static final HostedOptionKey<String> TraceObjectInstantiation = new HostedOptionKey<>("");

@Option(help = "Prefix that is added to the names of entry point methods.")//
public static final HostedOptionKey<String> EntryPointNamePrefix = new HostedOptionKey<>("");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ public static String commandArgument(OptionKey<?> option, String value, String a
} else {
for (APIOption apiOption : apiOptions) {
String fixedValue = apiOption.fixedValue().length == 0 ? null : apiOption.fixedValue()[0];
if (apiOption.name().equals(apiOptionName)) {
if (apiOptionName == null || apiOption.name().equals(apiOptionName)) {
if (fixedValue == null) {
return APIOption.Utils.name(apiOption) + "=" + value;
} else if (value.equals(fixedValue)) {
Expand Down
Loading

0 comments on commit 8c210f7

Please sign in to comment.