use of com.oracle.svm.hosted.code.NativeMethodSubstitutionProcessor in project graal by oracle.
the class NativeImageGenerator method doRun.
@SuppressWarnings("try")
private void doRun(Map<Method, CEntryPointData> entryPoints, Method mainEntryPoint, JavaMainSupport javaMainSupport, String imageName, AbstractBootImage.NativeImageKind k, SubstitutionProcessor harnessSubstitutions, ForkJoinPool compilationExecutor, ForkJoinPool analysisExecutor) {
List<HostedMethod> hostedEntryPoints = new ArrayList<>();
NativeLibraries nativeLibs;
SVMHost svmHost;
AnalysisMetaAccess aMetaAccess;
SnippetReflectionProvider aSnippetReflection;
HostedProviders aProviders;
Throwable error = null;
OptionValues options = HostedOptionValues.singleton();
SnippetReflectionProvider originalSnippetReflection = GraalAccess.getOriginalSnippetReflection();
try (DebugContext debug = DebugContext.create(options, new GraalDebugHandlersFactory(originalSnippetReflection))) {
try (Indent indent = debug.logAndIndent("start analysis pass")) {
try (StopTimer t = new Timer("setup").start()) {
// TODO Make customizable via command line parameter.
Platform platform = defaultPlatform();
TargetDescription target = createTarget(platform);
OSInterface osInterface = createOSInterface(loader);
ObjectLayout objectLayout = new ObjectLayout(target, SubstrateAMD64Backend.getDeoptScatchSpace());
CompressEncoding compressEncoding = new CompressEncoding(SubstrateOptions.UseHeapBaseRegister.getValue() ? 1 : 0, 0);
ImageSingletons.add(Platform.class, platform);
ImageSingletons.add(TargetDescription.class, target);
ImageSingletons.add(OSInterface.class, osInterface);
ImageSingletons.add(ObjectLayout.class, objectLayout);
ImageSingletons.add(CompressEncoding.class, compressEncoding);
if (javaMainSupport != null) {
ImageSingletons.add(JavaMainSupport.class, javaMainSupport);
}
Providers originalProviders = GraalAccess.getOriginalProviders();
MetaAccessProvider originalMetaAccess = originalProviders.getMetaAccess();
AnalysisPolicy analysisPolicy;
if (PointstoOptions.AllocationSiteSensitiveHeap.getValue(options)) {
// context sensitive analysis
analysisPolicy = new SVMBytecodeAnalysisPolicy(options);
} else {
// context insensitive analysis
analysisPolicy = new SVMDefaultAnalysisPolicy(options);
}
svmHost = new SVMHost(options, platform, analysisPolicy, loader.getClassLoader());
featureHandler.registerFeatures(loader);
AfterRegistrationAccessImpl access = new AfterRegistrationAccessImpl(featureHandler, loader, originalMetaAccess);
featureHandler.forEachFeature(feature -> feature.afterRegistration(access));
registerEntryPoints(entryPoints);
/*
* Check if any configuration factory class was registered. If not, register the
* basic one.
*/
HostedConfiguration.setDefaultIfEmpty();
GraalConfiguration.setDefaultIfEmpty();
registerEntryPoints(entryPoints);
CFunctionSubstitutionProcessor cfunctionSubstitutions = new CFunctionSubstitutionProcessor();
AnnotationSubstitutionProcessor annotationSubstitutions = new DeclarativeSubstitutionProcessor(loader, originalMetaAccess);
ImageSingletons.add(AnnotationSubstitutionProcessor.class, annotationSubstitutions);
annotationSubstitutions.init();
UnsafeAutomaticSubstitutionProcessor automaticSubstitutions = new UnsafeAutomaticSubstitutionProcessor(annotationSubstitutions);
ImageSingletons.add(UnsafeAutomaticSubstitutionProcessor.class, automaticSubstitutions);
automaticSubstitutions.init(originalMetaAccess);
SubstitutionProcessor substitutions = SubstitutionProcessor.chainUpInOrder(harnessSubstitutions, new AnnotationSupport(originalMetaAccess, originalSnippetReflection), annotationSubstitutions, cfunctionSubstitutions, automaticSubstitutions);
aUniverse = new AnalysisUniverse(svmHost, target, substitutions, originalMetaAccess, originalSnippetReflection, new SubstrateSnippetReflectionProvider());
aMetaAccess = new AnalysisMetaAccess(aUniverse, originalMetaAccess);
// native libraries
AnalysisConstantReflectionProvider aConstantReflection = new AnalysisConstantReflectionProvider(svmHost, aUniverse, originalProviders.getConstantReflection());
AnalysisConstantFieldProvider aConstantFieldProvider = new AnalysisConstantFieldProvider(aUniverse, aMetaAccess);
aSnippetReflection = new HostedSnippetReflectionProvider(svmHost);
nativeLibs = processNativeLibraryImports(aMetaAccess, aConstantReflection, aSnippetReflection);
/*
* Install all snippets so that the types, methods, and fields used in the
* snippets get added to the universe.
*/
ForeignCallsProvider aForeignCalls = new SubstrateForeignCallsProvider();
LoweringProvider aLoweringProvider = SubstrateLoweringProvider.create(aMetaAccess, null);
StampProvider aStampProvider = new SubstrateStampProvider(aMetaAccess);
WordTypes aWordTypes = new WordTypes(aMetaAccess, FrameAccess.getWordKind());
aProviders = new HostedProviders(aMetaAccess, null, aConstantReflection, aConstantFieldProvider, aForeignCalls, aLoweringProvider, null, aStampProvider, aSnippetReflection, aWordTypes);
BytecodeProvider bytecodeProvider = new ResolvedJavaMethodBytecodeProvider();
SubstrateReplacements aReplacements = new SubstrateReplacements(options, aProviders, aSnippetReflection, bytecodeProvider, target, new SubstrateGraphMakerFactory(aWordTypes));
aProviders = new HostedProviders(aMetaAccess, null, aConstantReflection, aConstantFieldProvider, aForeignCalls, aLoweringProvider, aReplacements, aStampProvider, aSnippetReflection, aWordTypes);
bigbang = new Inflation(options, aUniverse, aProviders, svmHost, analysisExecutor);
/*
* Eagerly register all target fields of recomputed value fields as unsafe
* accessed.
*/
annotationSubstitutions.processComputedValueFields(bigbang);
try (Indent indent2 = debug.logAndIndent("process startup initializers")) {
DuringSetupAccessImpl config = new DuringSetupAccessImpl(featureHandler, loader, bigbang, svmHost);
featureHandler.forEachFeature(feature -> feature.duringSetup(config));
}
NativeImageGenerator.registerGraphBuilderPlugins(featureHandler, null, aProviders, aMetaAccess, aUniverse, null, null, nativeLibs, loader, true, true);
registerReplacements(debug, featureHandler, null, aProviders, aProviders.getSnippetReflection(), true);
/*
* Install feature supported substitutions.
*/
SubstitutionProcessor[] featureNativeSubstitutions = aUniverse.getFeatureNativeSubstitutions();
if (featureNativeSubstitutions.length > 0) {
SubstitutionProcessor chain = SubstitutionProcessor.chainUpInOrder(featureNativeSubstitutions);
SubstitutionProcessor nativeSubstitutionProcessor = new NativeMethodSubstitutionProcessor(chain, aReplacements);
SubstitutionProcessor.extendsTheChain(substitutions, new SubstitutionProcessor[] { nativeSubstitutionProcessor });
}
SubstitutionProcessor.extendsTheChain(substitutions, aUniverse.getFeatureSubstitutions());
/*
* System classes and fields are necessary to tell the static analysis that
* certain things really "exist". The most common reason for that is that there
* are no instances and allocations of these classes seen during the static
* analysis. The heap chunks are one good example.
*/
try (Indent indent2 = debug.logAndIndent("add initial classes/fields/methods")) {
bigbang.addSystemClass(Object.class, false, false).registerAsInHeap();
bigbang.addSystemField(DynamicHub.class, "vtable");
bigbang.addSystemClass(String.class, false, false).registerAsInHeap();
bigbang.addSystemClass(String[].class, false, false).registerAsInHeap();
bigbang.addSystemField(String.class, "value").registerAsInHeap();
bigbang.addSystemClass(long[].class, false, false).registerAsInHeap();
bigbang.addSystemClass(byte[].class, false, false).registerAsInHeap();
bigbang.addSystemClass(byte[][].class, false, false).registerAsInHeap();
bigbang.addSystemClass(Object[].class, false, false).registerAsInHeap();
bigbang.addSystemClass(CFunctionPointer[].class, false, false).registerAsInHeap();
bigbang.addSystemClass(PointerBase[].class, false, false).registerAsInHeap();
// Fields of BootImageInfo that get patched via relocation to addresses
// to the partitions of the native image heap.
bigbang.addSystemStaticField(NativeImageInfo.class, "firstReadOnlyPrimitiveObject").registerAsInHeap();
bigbang.addSystemStaticField(NativeImageInfo.class, "lastReadOnlyPrimitiveObject").registerAsInHeap();
bigbang.addSystemStaticField(NativeImageInfo.class, "firstReadOnlyReferenceObject").registerAsInHeap();
bigbang.addSystemStaticField(NativeImageInfo.class, "lastReadOnlyReferenceObject").registerAsInHeap();
bigbang.addSystemStaticField(NativeImageInfo.class, "firstWritablePrimitiveObject").registerAsInHeap();
bigbang.addSystemStaticField(NativeImageInfo.class, "lastWritablePrimitiveObject").registerAsInHeap();
bigbang.addSystemStaticField(NativeImageInfo.class, "firstWritableReferenceObject").registerAsInHeap();
bigbang.addSystemStaticField(NativeImageInfo.class, "lastWritableReferenceObject").registerAsInHeap();
// Graal uses it for type checks in the partial escape analysis phase.
bigbang.addSystemClass(Reference.class, false, false);
bigbang.addSystemClass(AllocationSite.class, false, false).registerAsInHeap();
bigbang.addSystemClass(AllocationCounter.class, false, false).registerAsInHeap();
bigbang.addSystemClass(AtomicReference.class, false, false).registerAsInHeap();
try {
/*
* TODO we want to get rid of these explicit registrations. All
* registered foreign calls should automatically be included in the
* static analysis.
*/
bigbang.addRootMethod(ArraycopySnippets.class.getDeclaredMethod("doArraycopy", Object.class, int.class, Object.class, int.class, int.class));
bigbang.addRootMethod(Object.class.getDeclaredMethod("getClass"));
if (NativeImageOptions.DeoptimizeAll.getValue()) {
bigbang.addRootMethod(DeoptTester.class.getMethod("deoptTest"));
}
} catch (NoSuchMethodException ex) {
throw VMError.shouldNotReachHere(ex);
}
for (JavaKind kind : JavaKind.values()) {
if (kind.isPrimitive() && kind != JavaKind.Void) {
bigbang.addSystemClass(kind.toJavaClass(), false, true);
bigbang.addSystemField(kind.toBoxedJavaClass(), "value");
bigbang.addSystemMethod(kind.toBoxedJavaClass(), "valueOf", kind.toJavaClass());
bigbang.addSystemMethod(kind.toBoxedJavaClass(), kind.getJavaName() + "Value");
}
}
entryPoints.forEach((method, entryPointData) -> CEntryPointCallStubSupport.singleton().registerStubForMethod(method, () -> entryPointData));
for (StructuredGraph graph : aReplacements.getSnippetGraphs(GraalOptions.TrackNodeSourcePosition.getValue(options))) {
MethodTypeFlowBuilder.registerUsedElements(bigbang, graph, null);
}
}
try (Indent indent2 = debug.logAndIndent("process analysis initializers")) {
BeforeAnalysisAccessImpl config = new BeforeAnalysisAccessImpl(featureHandler, loader, bigbang, svmHost, nativeLibs);
featureHandler.forEachFeature(feature -> feature.beforeAnalysis(config));
}
}
try (StopTimer t = new Timer("analysis").start()) {
Timer processFeaturesTimer = new Timer("(features)", false);
/*
* Iterate until analysis reaches a fixpoint
*/
DuringAnalysisAccessImpl config = new DuringAnalysisAccessImpl(featureHandler, loader, bigbang, svmHost, nativeLibs);
int numIterations = 0;
while (true) {
try (Indent indent2 = debug.logAndIndent("new analysis iteration")) {
/*
* Do the analysis (which itself is done in a similar iterative process)
*/
boolean analysisChanged = bigbang.finish();
numIterations++;
if (numIterations > 1000) {
/*
* Usually there are < 10 iterations. If we have so many iterations,
* we probably have an endless loop (but at least we have a
* performance problem because we re-start the analysis so often).
*/
throw VMError.shouldNotReachHere("Static analysis did not reach a fix point after " + numIterations + " iterations because a Feature keeps requesting new analysis iterations. The analysis itself " + (analysisChanged ? "DID" : "DID NOT") + " find a change in type states in the last iteration.");
}
/*
* Allow features to change the universe
*/
try (StopTimer t2 = processFeaturesTimer.start()) {
int numTypes = aUniverse.getTypes().size();
int numMethods = aUniverse.getMethods().size();
int numFields = aUniverse.getFields().size();
featureHandler.forEachFeature(feature -> feature.duringAnalysis(config));
if (!config.getAndResetRequireAnalysisIteration()) {
if (numTypes != aUniverse.getTypes().size() || numMethods != aUniverse.getMethods().size() || numFields != aUniverse.getFields().size()) {
throw UserError.abort("When a feature makes more types, methods, of fields reachable, it must require another analysis iteration via DuringAnalysisAccess.requireAnalysisIteration()");
}
break;
}
}
}
}
AfterAnalysisAccessImpl postConfig = new AfterAnalysisAccessImpl(featureHandler, loader, bigbang);
featureHandler.forEachFeature(feature -> feature.afterAnalysis(postConfig));
checkUniverse();
bigbang.typeFlowTimer.print();
bigbang.checkObjectsTimer.print();
processFeaturesTimer.print();
/* report the unsupported features by throwing UnsupportedFeatureException */
bigbang.getUnsupportedFeatures().report(bigbang);
} catch (UnsupportedFeatureException ufe) {
if (NativeImageOptions.ReportUnsupportedFeaturesCause.getValue() && ufe.getCause() != null) {
System.err.println("Original exception: ");
ufe.getCause().printStackTrace();
}
throw UserError.abort(ufe.getMessage());
}
} catch (InterruptedException ie) {
throw new InterruptImageBuilding();
} catch (RuntimeException | Error e) {
// Prevents swallowing exceptions when ReturnAfterAnalysis is true
error = e;
throw e;
} finally {
OnAnalysisExitAccess onExitConfig = new OnAnalysisExitAccessImpl(featureHandler, loader, bigbang);
featureHandler.forEachFeature(feature -> {
try {
feature.onAnalysisExit(onExitConfig);
} catch (Exception ex) {
System.err.println("Exception during " + feature.getClass().getName() + ".onAnalysisExit()");
}
});
if (AnalysisReportsOptions.PrintAnalysisCallTree.getValue(options)) {
String reportName = imageName.substring(imageName.lastIndexOf("/") + 1);
CallTreePrinter.print(bigbang, SubstrateOptions.Path.getValue(), reportName);
}
if (AnalysisReportsOptions.PrintImageObjectTree.getValue(options)) {
String reportName = imageName.substring(imageName.lastIndexOf("/") + 1);
ObjectTreePrinter.print(bigbang, SubstrateOptions.Path.getValue(), reportName);
}
if (PointstoOptions.ReportAnalysisStatistics.getValue(options)) {
PointsToStats.report(bigbang, imageName.replace("images/", ""));
}
if (PointstoOptions.PrintSynchronizedAnalysis.getValue(options)) {
TypeState allSynchronizedTypeState = bigbang.getAllSynchronizedTypeState();
String typesString = //
allSynchronizedTypeState.closeToAllInstantiated(bigbang) ? //
"close to all instantiated" : StreamSupport.stream(allSynchronizedTypeState.types().spliterator(), false).map(AnalysisType::getName).collect(Collectors.joining(", "));
System.out.println();
System.out.println("AllSynchronizedTypes");
System.out.println("Synchronized types #: " + allSynchronizedTypeState.typesCount());
System.out.println("Types: " + typesString);
System.out.println();
}
}
if (error == null && NativeImageOptions.ReturnAfterAnalysis.getValue()) {
return;
}
if (NativeImageOptions.ExitAfterAnalysis.getValue()) {
throw new InterruptImageBuilding("interrupted image construction as ExitAfterAnalysis is set");
}
NativeImageHeap heap;
HostedMethod mainEntryPointHostedStub;
HostedMetaAccess hMetaAccess;
SharedRuntimeConfigurationBuilder runtime;
try (StopTimer t = new Timer("universe").start()) {
hUniverse = new HostedUniverse(bigbang, svmHost);
hMetaAccess = new HostedMetaAccess(hUniverse, aMetaAccess);
new UniverseBuilder(aUniverse, aMetaAccess, hUniverse, hMetaAccess, HostedConfiguration.instance().createStaticAnalysisResultsBuilder(bigbang, hUniverse), bigbang.getUnsupportedFeatures()).build(debug);
runtime = new HostedRuntimeConfigurationBuilder(options, svmHost, hUniverse, hMetaAccess, aProviders).build();
registerGraphBuilderPlugins(featureHandler, runtime.getRuntimeConfig(), (HostedProviders) runtime.getRuntimeConfig().getProviders(), aMetaAccess, aUniverse, hMetaAccess, hUniverse, nativeLibs, loader, false, true);
if (NativeImageOptions.PrintUniverse.getValue()) {
printTypes();
}
/* Find the entry point methods in the hosted world. */
for (AnalysisMethod m : aUniverse.getMethods()) {
if (m.isEntryPoint()) {
HostedMethod found = hUniverse.lookup(m);
assert found != null;
hostedEntryPoints.add(found);
}
}
/* Find main entry point */
if (mainEntryPoint != null) {
AnalysisMethod analysisStub = CEntryPointCallStubSupport.singleton().getStubForMethod(mainEntryPoint);
mainEntryPointHostedStub = (HostedMethod) hMetaAccess.getUniverse().lookup(analysisStub);
assert hostedEntryPoints.contains(mainEntryPointHostedStub);
} else {
mainEntryPointHostedStub = null;
}
if (hostedEntryPoints.size() == 0) {
throw UserError.abort("Warning: no entry points found, i.e., no method annotated with @" + CEntryPoint.class.getSimpleName());
}
heap = new NativeImageHeap(aUniverse, hUniverse, hMetaAccess);
BeforeCompilationAccessImpl config = new BeforeCompilationAccessImpl(featureHandler, loader, aUniverse, hUniverse, hMetaAccess, heap);
featureHandler.forEachFeature(feature -> feature.beforeCompilation(config));
bigbang.getUnsupportedFeatures().report(bigbang);
} catch (UnsupportedFeatureException ufe) {
throw UserError.abort(ufe.getMessage());
}
recordMethodsWithStackValues();
recordRestrictHeapAccessCallees(aUniverse.getMethods());
/*
* After this point, all TypeFlow (and therefore also TypeState) objects are unreachable
* and can be garbage collected. This is important to keep the overall memory footprint
* low. However, this also means we no longer have complete call chain information. Only
* the summarized information stored in the StaticAnalysisResult objects is available
* after this point.
*/
bigbang.cleanupAfterAnalysis();
NativeImageCodeCache codeCache;
CompileQueue compileQueue;
try (StopTimer t = new Timer("compile").start()) {
compileQueue = HostedConfiguration.instance().createCompileQueue(debug, featureHandler, hUniverse, runtime, NativeImageOptions.DeoptimizeAll.getValue(), aSnippetReflection, compilationExecutor);
compileQueue.finish(debug);
/* release memory taken by graphs for the image writing */
hUniverse.getMethods().forEach(HostedMethod::clear);
codeCache = new NativeImageCodeCache(compileQueue.getCompilations(), heap);
codeCache.layoutMethods(debug);
codeCache.layoutConstants();
AfterCompilationAccessImpl config = new AfterCompilationAccessImpl(featureHandler, loader, aUniverse, hUniverse, hMetaAccess, heap);
featureHandler.forEachFeature(feature -> feature.afterCompilation(config));
}
try (Indent indent = debug.logAndIndent("create native image")) {
try (DebugContext.Scope buildScope = debug.scope("CreateBootImage")) {
try (StopTimer t = new Timer("image").start()) {
// Start building the model of the native image heap.
heap.addInitialObjects(debug);
// Then build the model of the code cache, which can
// add objects to the native image heap.
codeCache.addConstantsToHeap(debug);
// Finish building the model of the native image heap.
heap.addTrailingObjects(debug);
AfterHeapLayoutAccessImpl config = new AfterHeapLayoutAccessImpl(featureHandler, loader, hMetaAccess);
featureHandler.forEachFeature(feature -> feature.afterHeapLayout(config));
this.image = AbstractBootImage.create(k, hUniverse, hMetaAccess, nativeLibs, heap, codeCache, hostedEntryPoints, mainEntryPointHostedStub);
image.build(debug);
if (NativeImageOptions.PrintUniverse.getValue()) {
/*
* This debug output must be printed _after_ and not _during_ image
* building, because it adds some PrintStream objects to static fields,
* which disrupts the heap.
*/
codeCache.printCompilationResults();
}
}
}
}
BeforeImageWriteAccessImpl beforeConfig = new BeforeImageWriteAccessImpl(featureHandler, loader, imageName, image, runtime.getRuntimeConfig(), aUniverse, hUniverse, optionProvider, hMetaAccess);
featureHandler.forEachFeature(feature -> feature.beforeImageWrite(beforeConfig));
try (StopTimer t = new Timer("write").start()) {
/*
* This will write the debug info too -- i.e. we may be writing more than one file,
* if the debug info is in a separate file. We need to push writing the file to the
* image implementation, because whether the debug info and image share a file or
* not is an implementation detail of the image.
*/
Path tmpDir = tempDirectory();
Path imagePath = image.write(debug, generatedFiles(HostedOptionValues.singleton()), tmpDir, imageName, beforeConfig);
AfterImageWriteAccessImpl afterConfig = new AfterImageWriteAccessImpl(featureHandler, loader, imagePath, tmpDir, image.getBootImageKind());
featureHandler.forEachFeature(feature -> feature.afterImageWrite(afterConfig));
}
}
}
Aggregations