wasm: when building tests, resolve absolute paths to source files in DWARF

This commit is contained in:
Alexey Andreev 2023-09-26 23:02:16 +02:00
parent 5a0c418389
commit b7cf7b593c
7 changed files with 140 additions and 3 deletions

View File

@ -43,6 +43,7 @@ import org.teavm.backend.wasm.binary.BinaryWriter;
import org.teavm.backend.wasm.debug.DebugInfoBuilder;
import org.teavm.backend.wasm.generate.DwarfClassGenerator;
import org.teavm.backend.wasm.generate.DwarfGenerator;
import org.teavm.backend.wasm.generate.SourceFileResolver;
import org.teavm.backend.wasm.generate.WasmClassGenerator;
import org.teavm.backend.wasm.generate.WasmDependencyListener;
import org.teavm.backend.wasm.generate.WasmGenerationContext;
@ -209,6 +210,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
private boolean hasThreads;
private WasmRuntimeType runtimeType = WasmRuntimeType.TEAVM;
private ReportingWasmBinaryStatsCollector statsCollector;
private SourceFileResolver sourceFileResolver;
@Override
public void setController(TeaVMTargetController controller) {
@ -309,6 +311,10 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
this.runtimeType = runtimeType;
}
public void setSourceFileResolver(SourceFileResolver sourceFileResolver) {
this.sourceFileResolver = sourceFileResolver;
}
@Override
public WasmRuntimeType getRuntimeType() {
return runtimeType;
@ -476,7 +482,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
var names = new NameProviderWithSpecialNames(new WasmNameProvider(), controller.getUnprocessedClassSource());
var metadataRequirements = new ClassMetadataRequirements(controller.getDependencyInfo());
var dwarfGenerator = debugging ? new DwarfGenerator() : null;
var dwarfGenerator = debugging ? new DwarfGenerator(sourceFileResolver) : null;
if (dwarfGenerator != null) {
dwarfGenerator.begin();
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 2023 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.backend.wasm.generate;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DirectorySourceFileResolver implements SourceFileResolver {
private List<File> directories;
private Map<String, Wrapper> cache = new HashMap<>();
public DirectorySourceFileResolver(List<File> directories) {
this.directories = List.copyOf(directories);
}
@Override
public String resolveFile(String file) {
return cache.computeIfAbsent(file, f -> {
for (var dir : directories) {
var candidate = new File(dir, f);
if (candidate.isFile()) {
return new Wrapper(candidate.getAbsolutePath());
}
}
return new Wrapper(null);
}).value;
}
private static class Wrapper {
final String value;
Wrapper(String value) {
this.value = value;
}
}
}

View File

@ -42,9 +42,13 @@ public class DwarfGenerator {
private DwarfPlaceholder endOfSection;
public final DwarfStrings strings = new DwarfStrings();
private DwarfStrings lineStrings = new DwarfStrings();
private DwarfLinesGenerator lines = new DwarfLinesGenerator(lineStrings);
private DwarfLinesGenerator lines;
private Marker highPcMarker;
public DwarfGenerator(SourceFileResolver sourceFileResolver) {
lines = new DwarfLinesGenerator(lineStrings, sourceFileResolver);
}
public void begin() {
endOfSection = infoWriter.placeholder(4);
lines.begin();

View File

@ -26,6 +26,8 @@ import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_LNS_COPY;
import static org.teavm.backend.wasm.dwarf.DwarfConstants.DW_LNS_SET_FILE;
import com.carrotsearch.hppc.ObjectIntHashMap;
import com.carrotsearch.hppc.ObjectIntMap;
import java.util.HashMap;
import java.util.Map;
import org.teavm.backend.wasm.blob.Blob;
import org.teavm.backend.wasm.blob.Marker;
@ -37,6 +39,7 @@ class DwarfLinesGenerator {
Blob blob = new Blob();
private DwarfStrings strings;
private SourceFileResolver sourceFileResolver;
private Blob instructionsBlob = new Blob();
private Marker unitLengthMarker;
private Marker headerLengthMarker;
@ -48,9 +51,11 @@ class DwarfLinesGenerator {
private int file = 1;
private int line = 1;
private boolean sequenceStarted;
private Map<String, String> resolvedFileMap = new HashMap<>();
DwarfLinesGenerator(DwarfStrings strings) {
DwarfLinesGenerator(DwarfStrings strings, SourceFileResolver sourceFileResolver) {
this.strings = strings;
this.sourceFileResolver = sourceFileResolver;
}
void begin() {
@ -138,6 +143,7 @@ class DwarfLinesGenerator {
}
private int fileRef(String path) {
path = resolvePath(path);
var ref = fileIndexes.getOrDefault(path, -1);
if (ref < 0) {
var nameIndex = path.lastIndexOf('/') + 1;
@ -154,6 +160,16 @@ class DwarfLinesGenerator {
return ref;
}
private String resolvePath(String path) {
if (sourceFileResolver == null) {
return path;
}
return resolvedFileMap.computeIfAbsent(path, p -> {
var result = sourceFileResolver.resolveFile(p);
return result != null ? result : p;
});
}
private int dirRef(String path) {
var ref = dirIndexes.getOrDefault(path, -1);
if (ref < 0) {

View File

@ -0,0 +1,20 @@
/*
* Copyright 2023 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.backend.wasm.generate;
public interface SourceFileResolver {
String resolveFile(String file);
}

View File

@ -61,5 +61,28 @@ tasks.test {
systemProperty("teavm.junit.c.compiler", providers.gradleProperty("teavm.tests.c.compiler")
.orElse("compile-c-unix-fast.sh").get())
jvmArgumentProviders += object : CommandLineArgumentProvider {
override fun asArguments(): Iterable<String> {
val dependencies = configurations.testRuntimeClasspath.get()
.incoming.resolutionResult.allDependencies
.asSequence()
.filterIsInstance<ResolvedDependencyResult>()
.map { it.requested }
.filterIsInstance<ProjectComponentSelector>()
.map { project.rootProject.project(it.projectPath) }
val projects = dependencies + project
val dirs = projects.map { it.layout.projectDirectory }.flatMap {
sequenceOf(
it.dir("src/main/java"),
it.dir("src/test/java")
)
}
val result = dirs
.map { it.asFile.absolutePath }
.joinToString(File.pathSeparator)
return listOf("-Dteavm.junit.sourceDirs=$result")
}
}
maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).coerceAtLeast(1)
}

View File

@ -39,6 +39,7 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.WeakHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@ -61,6 +62,7 @@ import org.teavm.backend.c.generate.CNameProvider;
import org.teavm.backend.javascript.JavaScriptTarget;
import org.teavm.backend.wasm.WasmRuntimeType;
import org.teavm.backend.wasm.WasmTarget;
import org.teavm.backend.wasm.generate.DirectorySourceFileResolver;
import org.teavm.callgraph.CallGraph;
import org.teavm.debugging.information.DebugInformation;
import org.teavm.debugging.information.DebugInformationBuilder;
@ -117,6 +119,7 @@ public class TeaVMTestRunner extends Runner implements Filterable {
private static final String MINIFIED = "teavm.junit.minified";
private static final String OPTIMIZED = "teavm.junit.optimized";
private static final String FAST_ANALYSIS = "teavm.junit.fastAnalysis";
private static final String SOURCE_DIRS = "teavm.junit.sourceDirs";
private Class<?> testClass;
private boolean isWholeClassCompilation;
@ -1125,6 +1128,20 @@ public class TeaVMTestRunner extends Runner implements Filterable {
Supplier<WasmTarget> targetSupplier = () -> {
WasmTarget target = new WasmTarget();
target.setRuntimeType(runtimeType);
var sourceDirs = System.getProperty(SOURCE_DIRS);
if (sourceDirs != null) {
var dirs = new ArrayList<File>();
for (var tokenizer = new StringTokenizer(sourceDirs, Character.toString(File.pathSeparatorChar));
tokenizer.hasMoreTokens();) {
var dir = new File(tokenizer.nextToken());
if (dir.isDirectory()) {
dirs.add(dir);
}
}
if (!dirs.isEmpty()) {
target.setSourceFileResolver(new DirectorySourceFileResolver(dirs));
}
}
return target;
};
return compile(configuration, targetSupplier, TestNativeEntryPoint.class.getName(), path,