Search in sources :

Example 1 with Support

use of com.oracle.svm.jvmtiagentbase.Support in project graal by oracle.

the class NativeImageAgent method onLoadCallback.

@Override
protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks callbacks, String options) {
    String traceOutputFile = null;
    String configOutputDir = null;
    ConfigurationSet mergeConfigs = new ConfigurationSet();
    ConfigurationSet omittedConfigs = new ConfigurationSet();
    boolean builtinCallerFilter = true;
    boolean builtinHeuristicFilter = true;
    List<String> callerFilterFiles = new ArrayList<>();
    List<String> accessFilterFiles = new ArrayList<>();
    boolean experimentalClassLoaderSupport = true;
    boolean experimentalClassDefineSupport = false;
    boolean experimentalOmitClasspathConfig = false;
    boolean build = false;
    boolean configurationWithOrigins = false;
    // in seconds
    int configWritePeriod = -1;
    // in seconds
    int configWritePeriodInitialDelay = 1;
    boolean trackReflectionMetadata = true;
    String[] tokens = !options.isEmpty() ? options.split(",") : new String[0];
    for (String token : tokens) {
        if (token.startsWith("trace-output=")) {
            if (traceOutputFile != null) {
                return usage(1, "cannot specify trace-output= more than once.");
            }
            traceOutputFile = getTokenValue(token);
        } else if (token.startsWith("config-output-dir=") || token.startsWith("config-merge-dir=")) {
            if (configOutputDir != null) {
                return usage(1, "cannot specify more than one of config-output-dir= or config-merge-dir=.");
            }
            configOutputDir = transformPath(getTokenValue(token));
            if (token.startsWith("config-merge-dir=")) {
                mergeConfigs.addDirectory(Paths.get(configOutputDir));
            }
        } else if (token.startsWith("config-to-omit=")) {
            String omittedConfigDir = getTokenValue(token);
            omittedConfigDir = transformPath(omittedConfigDir);
            omittedConfigs.addDirectory(Paths.get(omittedConfigDir));
        } else if (token.equals("experimental-omit-config-from-classpath")) {
            experimentalOmitClasspathConfig = true;
        } else if (token.startsWith("experimental-omit-config-from-classpath=")) {
            experimentalOmitClasspathConfig = Boolean.parseBoolean(getTokenValue(token));
        } else if (token.startsWith("restrict-all-dir") || token.equals("restrict") || token.startsWith("restrict=")) {
            warn("restrict mode is no longer supported, ignoring option: " + token);
        } else if (token.equals("no-builtin-caller-filter")) {
            builtinCallerFilter = false;
        } else if (token.startsWith("builtin-caller-filter=")) {
            builtinCallerFilter = Boolean.parseBoolean(getTokenValue(token));
        } else if (token.equals("no-builtin-heuristic-filter")) {
            builtinHeuristicFilter = false;
        } else if (token.startsWith("builtin-heuristic-filter=")) {
            builtinHeuristicFilter = Boolean.parseBoolean(getTokenValue(token));
        } else if (token.equals("no-filter")) {
            // legacy
            builtinCallerFilter = false;
            builtinHeuristicFilter = false;
        } else if (token.startsWith("no-filter=")) {
            // legacy
            builtinCallerFilter = !Boolean.parseBoolean(getTokenValue(token));
            builtinHeuristicFilter = builtinCallerFilter;
        } else if (token.startsWith("caller-filter-file=")) {
            callerFilterFiles.add(getTokenValue(token));
        } else if (token.startsWith("access-filter-file=")) {
            accessFilterFiles.add(getTokenValue(token));
        } else if (token.equals("experimental-class-loader-support")) {
            experimentalClassLoaderSupport = true;
        } else if (token.startsWith("experimental-class-loader-support=")) {
            experimentalClassLoaderSupport = Boolean.parseBoolean(getTokenValue(token));
        } else if (token.equals("experimental-class-define-support")) {
            experimentalClassDefineSupport = true;
        } else if (token.startsWith("experimental-class-define-support=")) {
            experimentalClassDefineSupport = Boolean.parseBoolean(getTokenValue(token));
        } else if (token.startsWith("config-write-period-secs=")) {
            configWritePeriod = parseIntegerOrNegative(getTokenValue(token));
            if (configWritePeriod <= 0) {
                return usage(1, "config-write-period-secs must be an integer greater than 0");
            }
        } else if (token.startsWith("config-write-initial-delay-secs=")) {
            configWritePeriodInitialDelay = parseIntegerOrNegative(getTokenValue(token));
            if (configWritePeriodInitialDelay < 0) {
                return usage(1, "config-write-initial-delay-secs must be an integer greater or equal to 0");
            }
        } else if (token.equals("build")) {
            build = true;
        } else if (token.startsWith("build=")) {
            build = Boolean.parseBoolean(getTokenValue(token));
        } else if (token.equals("experimental-configuration-with-origins")) {
            configurationWithOrigins = true;
        } else if (token.equals("track-reflection-metadata")) {
            trackReflectionMetadata = true;
        } else if (token.startsWith("track-reflection-metadata=")) {
            trackReflectionMetadata = Boolean.parseBoolean(getTokenValue(token));
        } else {
            return usage(1, "unknown option: '" + token + "'.");
        }
    }
    if (traceOutputFile == null && configOutputDir == null && !build) {
        configOutputDir = transformPath(AGENT_NAME + "_config-pid{pid}-{datetime}/");
        inform("no output/build options provided, tracking dynamic accesses and writing configuration to directory: " + configOutputDir);
    }
    if (configurationWithOrigins && !mergeConfigs.isEmpty()) {
        configurationWithOrigins = false;
        inform("using configuration with origins with configuration merging is currently unsupported. Disabling configuration with origins mode.");
    }
    if (configurationWithOrigins) {
        warn("using experimental configuration with origins mode. Note that native-image cannot process these files, and this flag may change or be removed without a warning!");
    }
    RuleNode callerFilter = null;
    if (!builtinCallerFilter) {
        callerFilter = RuleNode.createRoot();
        callerFilter.addOrGetChildren("**", RuleNode.Inclusion.Include);
    }
    if (!callerFilterFiles.isEmpty()) {
        if (callerFilter == null) {
            callerFilter = AccessAdvisor.copyBuiltinCallerFilterTree();
        }
        if (!parseFilterFiles(callerFilter, callerFilterFiles)) {
            return 1;
        }
    }
    RuleNode accessFilter = null;
    if (!accessFilterFiles.isEmpty()) {
        accessFilter = AccessAdvisor.copyBuiltinAccessFilterTree();
        if (!parseFilterFiles(accessFilter, accessFilterFiles)) {
            return 1;
        }
    }
    final MethodInfoRecordKeeper recordKeeper = new MethodInfoRecordKeeper(configurationWithOrigins);
    final Supplier<InterceptedState> interceptedStateSupplier = configurationWithOrigins ? EagerlyLoadedJavaStackAccess.stackAccessSupplier() : OnDemandJavaStackAccess.stackAccessSupplier();
    if (configOutputDir != null) {
        if (traceOutputFile != null) {
            return usage(1, "can only once specify exactly one of trace-output=, config-output-dir= or config-merge-dir=.");
        }
        try {
            configOutputDirPath = Files.createDirectories(Path.of(configOutputDir));
            configOutputLockFilePath = configOutputDirPath.resolve(ConfigurationFile.LOCK_FILE_NAME);
            try {
                Files.writeString(configOutputLockFilePath, Long.toString(ProcessProperties.getProcessID()), StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE);
            } catch (FileAlreadyExistsException e) {
                String process;
                try {
                    process = Files.readString(configOutputLockFilePath).stripTrailing();
                } catch (Exception ignored) {
                    process = "(unknown)";
                }
                return error(2, "Output directory '" + configOutputDirPath + "' is locked by process " + process + ", " + "which means another agent instance is already writing to this directory. " + "Only one agent instance can safely write to a specific target directory at the same time. " + "Unless file '" + ConfigurationFile.LOCK_FILE_NAME + "' is a leftover from an earlier process that terminated abruptly, it is unsafe to delete it. " + "For running multiple processes with agents at the same time to create a single configuration, read Agent.md " + "or https://www.graalvm.org/reference-manual/native-image/Agent/ on how to use the native-image-configure tool.");
            }
            if (experimentalOmitClasspathConfig) {
                ignoreConfigFromClasspath(jvmti, omittedConfigs);
            }
            AccessAdvisor advisor = createAccessAdvisor(builtinHeuristicFilter, callerFilter, accessFilter);
            TraceProcessor omittedConfigProcessor = null;
            Predicate<String> shouldExcludeClassesWithHash = null;
            if (!omittedConfigs.isEmpty()) {
                Function<IOException, Exception> ignore = e -> {
                    warn("Failed to load omitted config: " + e);
                    return null;
                };
                omittedConfigProcessor = new TraceProcessor(advisor, omittedConfigs.loadJniConfig(ignore), omittedConfigs.loadReflectConfig(ignore), omittedConfigs.loadProxyConfig(ignore), omittedConfigs.loadResourceConfig(ignore), omittedConfigs.loadSerializationConfig(ignore), omittedConfigs.loadPredefinedClassesConfig(null, null, ignore), null);
                shouldExcludeClassesWithHash = omittedConfigProcessor.getPredefinedClassesConfiguration()::containsClassWithHash;
            }
            if (configurationWithOrigins) {
                ConfigurationWithOriginsResultWriter writer = new ConfigurationWithOriginsResultWriter(advisor, recordKeeper);
                tracer = writer;
                tracingResultWriter = writer;
            } else {
                Path[] predefinedClassDestDirs = { Files.createDirectories(configOutputDirPath.resolve(ConfigurationFile.PREDEFINED_CLASSES_AGENT_EXTRACTED_SUBDIR)) };
                Function<IOException, Exception> handler = e -> {
                    if (e instanceof NoSuchFileException) {
                        warn("file " + ((NoSuchFileException) e).getFile() + " for merging could not be found, skipping");
                        return null;
                    } else if (e instanceof FileNotFoundException) {
                        warn("could not open configuration file: " + e);
                        return null;
                    }
                    // rethrow
                    return e;
                };
                TraceProcessor processor = new TraceProcessor(advisor, mergeConfigs.loadJniConfig(handler), mergeConfigs.loadReflectConfig(handler), mergeConfigs.loadProxyConfig(handler), mergeConfigs.loadResourceConfig(handler), mergeConfigs.loadSerializationConfig(handler), mergeConfigs.loadPredefinedClassesConfig(predefinedClassDestDirs, shouldExcludeClassesWithHash, handler), omittedConfigProcessor);
                ConfigurationResultWriter writer = new ConfigurationResultWriter(processor);
                tracer = writer;
                tracingResultWriter = writer;
            }
            expectedConfigModifiedBefore = getMostRecentlyModified(configOutputDirPath, getMostRecentlyModified(configOutputLockFilePath, null));
        } catch (Throwable t) {
            return error(2, t.toString());
        }
    } else if (traceOutputFile != null) {
        try {
            Path path = Paths.get(transformPath(traceOutputFile));
            TraceFileWriter writer = new TraceFileWriter(path);
            tracer = writer;
            tracingResultWriter = writer;
        } catch (Throwable t) {
            return error(2, t.toString());
        }
    }
    if (build) {
        int status = buildImage(jvmti);
        if (status == 0) {
            System.exit(status);
        }
        return status;
    }
    try {
        BreakpointInterceptor.onLoad(jvmti, callbacks, tracer, this, interceptedStateSupplier, experimentalClassLoaderSupport, experimentalClassDefineSupport, trackReflectionMetadata);
    } catch (Throwable t) {
        return error(3, t.toString());
    }
    try {
        JniCallInterceptor.onLoad(tracer, this, interceptedStateSupplier);
    } catch (Throwable t) {
        return error(4, t.toString());
    }
    setupExecutorServiceForPeriodicConfigurationCapture(configWritePeriod, configWritePeriodInitialDelay);
    return 0;
}
Also used : NoSuchFileException(java.nio.file.NoSuchFileException) Arrays(java.util.Arrays) ProcessProperties(org.graalvm.nativeimage.ProcessProperties) Date(java.util.Date) EagerlyLoadedJavaStackAccess(com.oracle.svm.agent.stackaccess.EagerlyLoadedJavaStackAccess) FileTime(java.nio.file.attribute.FileTime) ConfigurationResultWriter(com.oracle.svm.agent.tracing.ConfigurationResultWriter) NativeImage(com.oracle.svm.driver.NativeImage) RuleNode(com.oracle.svm.configure.filters.RuleNode) JNIJavaVM(com.oracle.svm.jni.nativeapi.JNIJavaVM) JNIEnvironment(com.oracle.svm.jni.nativeapi.JNIEnvironment) TraceFileWriter(com.oracle.svm.agent.tracing.TraceFileWriter) JNIObjectHandle(com.oracle.svm.jni.nativeapi.JNIObjectHandle) FilterConfigurationParser(com.oracle.svm.configure.filters.FilterConfigurationParser) Path(java.nio.file.Path) AgentMetaInfProcessor(com.oracle.svm.agent.ignoredconfig.AgentMetaInfProcessor) DateFormat(java.text.DateFormat) Support(com.oracle.svm.jvmtiagentbase.Support) TimeZone(java.util.TimeZone) Predicate(java.util.function.Predicate) Feature(org.graalvm.nativeimage.hosted.Feature) StandardOpenOption(java.nio.file.StandardOpenOption) ScheduledThreadPoolExecutor(java.util.concurrent.ScheduledThreadPoolExecutor) ConfigurationWithOriginsResultWriter(com.oracle.svm.agent.predicatedconfig.ConfigurationWithOriginsResultWriter) FileNotFoundException(java.io.FileNotFoundException) JvmtiEventCallbacks(com.oracle.svm.jvmtiagentbase.jvmti.JvmtiEventCallbacks) List(java.util.List) JNIHandleSet(com.oracle.svm.jvmtiagentbase.JNIHandleSet) InterceptedState(com.oracle.svm.agent.stackaccess.InterceptedState) Pattern(java.util.regex.Pattern) JvmtiEnv(com.oracle.svm.jvmtiagentbase.jvmti.JvmtiEnv) NativeImageMetaInfWalker(com.oracle.svm.driver.metainf.NativeImageMetaInfWalker) ConcurrentModificationException(java.util.ConcurrentModificationException) SimpleDateFormat(java.text.SimpleDateFormat) Function(java.util.function.Function) Supplier(java.util.function.Supplier) StandardCopyOption(java.nio.file.StandardCopyOption) ArrayList(java.util.ArrayList) Platform(org.graalvm.nativeimage.Platform) ConfigurationSet(com.oracle.svm.configure.config.ConfigurationSet) TracingResultWriter(com.oracle.svm.agent.tracing.core.TracingResultWriter) OnDemandJavaStackAccess(com.oracle.svm.agent.stackaccess.OnDemandJavaStackAccess) Tracer(com.oracle.svm.agent.tracing.core.Tracer) JvmtiInterface(com.oracle.svm.jvmtiagentbase.jvmti.JvmtiInterface) JvmtiAgentBase(com.oracle.svm.jvmtiagentbase.JvmtiAgentBase) Files(java.nio.file.Files) TraceProcessor(com.oracle.svm.configure.trace.TraceProcessor) IOException(java.io.IOException) AccessAdvisor(com.oracle.svm.configure.trace.AccessAdvisor) SubstrateUtil(com.oracle.svm.core.SubstrateUtil) FileAlreadyExistsException(java.nio.file.FileAlreadyExistsException) TimeUnit(java.util.concurrent.TimeUnit) Paths(java.nio.file.Paths) ConfigurationFile(com.oracle.svm.core.configure.ConfigurationFile) AtomicMoveNotSupportedException(java.nio.file.AtomicMoveNotSupportedException) MethodInfoRecordKeeper(com.oracle.svm.agent.predicatedconfig.MethodInfoRecordKeeper) InterceptedState(com.oracle.svm.agent.stackaccess.InterceptedState) FileAlreadyExistsException(java.nio.file.FileAlreadyExistsException) ArrayList(java.util.ArrayList) NoSuchFileException(java.nio.file.NoSuchFileException) FileNotFoundException(java.io.FileNotFoundException) AccessAdvisor(com.oracle.svm.configure.trace.AccessAdvisor) ConfigurationResultWriter(com.oracle.svm.agent.tracing.ConfigurationResultWriter) Path(java.nio.file.Path) RuleNode(com.oracle.svm.configure.filters.RuleNode) TraceProcessor(com.oracle.svm.configure.trace.TraceProcessor) TraceFileWriter(com.oracle.svm.agent.tracing.TraceFileWriter) IOException(java.io.IOException) NoSuchFileException(java.nio.file.NoSuchFileException) FileNotFoundException(java.io.FileNotFoundException) ConcurrentModificationException(java.util.ConcurrentModificationException) IOException(java.io.IOException) FileAlreadyExistsException(java.nio.file.FileAlreadyExistsException) AtomicMoveNotSupportedException(java.nio.file.AtomicMoveNotSupportedException) ConfigurationSet(com.oracle.svm.configure.config.ConfigurationSet) ConfigurationWithOriginsResultWriter(com.oracle.svm.agent.predicatedconfig.ConfigurationWithOriginsResultWriter) MethodInfoRecordKeeper(com.oracle.svm.agent.predicatedconfig.MethodInfoRecordKeeper)

Aggregations

AgentMetaInfProcessor (com.oracle.svm.agent.ignoredconfig.AgentMetaInfProcessor)1 ConfigurationWithOriginsResultWriter (com.oracle.svm.agent.predicatedconfig.ConfigurationWithOriginsResultWriter)1 MethodInfoRecordKeeper (com.oracle.svm.agent.predicatedconfig.MethodInfoRecordKeeper)1 EagerlyLoadedJavaStackAccess (com.oracle.svm.agent.stackaccess.EagerlyLoadedJavaStackAccess)1 InterceptedState (com.oracle.svm.agent.stackaccess.InterceptedState)1 OnDemandJavaStackAccess (com.oracle.svm.agent.stackaccess.OnDemandJavaStackAccess)1 ConfigurationResultWriter (com.oracle.svm.agent.tracing.ConfigurationResultWriter)1 TraceFileWriter (com.oracle.svm.agent.tracing.TraceFileWriter)1 Tracer (com.oracle.svm.agent.tracing.core.Tracer)1 TracingResultWriter (com.oracle.svm.agent.tracing.core.TracingResultWriter)1 ConfigurationSet (com.oracle.svm.configure.config.ConfigurationSet)1 FilterConfigurationParser (com.oracle.svm.configure.filters.FilterConfigurationParser)1 RuleNode (com.oracle.svm.configure.filters.RuleNode)1 AccessAdvisor (com.oracle.svm.configure.trace.AccessAdvisor)1 TraceProcessor (com.oracle.svm.configure.trace.TraceProcessor)1 SubstrateUtil (com.oracle.svm.core.SubstrateUtil)1 ConfigurationFile (com.oracle.svm.core.configure.ConfigurationFile)1 NativeImage (com.oracle.svm.driver.NativeImage)1 NativeImageMetaInfWalker (com.oracle.svm.driver.metainf.NativeImageMetaInfWalker)1 JNIEnvironment (com.oracle.svm.jni.nativeapi.JNIEnvironment)1