Skip to content

Commit

Permalink
Refactor ClassFinder into interface
Browse files Browse the repository at this point in the history
  • Loading branch information
lucko committed Jul 18, 2024
1 parent 1b75abc commit ed8eac5
Show file tree
Hide file tree
Showing 14 changed files with 191 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import me.lucko.spark.common.util.Configuration;
import me.lucko.spark.common.util.SparkStaticLogger;
import me.lucko.spark.common.util.TemporaryFiles;
import me.lucko.spark.common.util.classfinder.ClassFinder;
import me.lucko.spark.common.ws.TrustedKeyStore;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
Expand Down Expand Up @@ -285,6 +286,10 @@ public ClassSourceLookup createClassSourceLookup() {
return this.plugin.createClassSourceLookup();
}

public ClassFinder createClassFinder() {
return this.plugin.createClassFinder();
}

public TickStatistics getTickStatistics() {
return this.tickStatistics;
}
Expand Down
15 changes: 15 additions & 0 deletions spark-common/src/main/java/me/lucko/spark/common/SparkPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
import me.lucko.spark.common.sampler.source.SourceMetadata;
import me.lucko.spark.common.tick.TickHook;
import me.lucko.spark.common.tick.TickReporter;
import me.lucko.spark.common.util.classfinder.ClassFinder;
import me.lucko.spark.common.util.classfinder.FallbackClassFinder;
import me.lucko.spark.common.util.classfinder.InstrumentationClassFinder;

import java.nio.file.Path;
import java.util.Collection;
Expand Down Expand Up @@ -149,6 +152,18 @@ default ClassSourceLookup createClassSourceLookup() {
return ClassSourceLookup.NO_OP;
}

/**
* Creates a class finder for the platform.
*
* @return the class finder
*/
default ClassFinder createClassFinder() {
return ClassFinder.combining(
new InstrumentationClassFinder(this),
FallbackClassFinder.INSTANCE
);
}

/**
* Gets a list of known sources (plugins/mods) on the platform.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ private Sampler.ExportProps getExportProps(SparkPlatform platform, CommandRespon
.creator(resp.senderData())
.comment(Iterables.getFirst(arguments.stringFlag("comment"), null))
.mergeMode(() -> {
MethodDisambiguator methodDisambiguator = new MethodDisambiguator();
MethodDisambiguator methodDisambiguator = new MethodDisambiguator(platform.createClassFinder());
return arguments.boolFlag("separate-parent-calls")
? MergeMode.separateParentCalls(methodDisambiguator)
: MergeMode.sameMethod(methodDisambiguator);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import me.lucko.spark.common.sampler.source.SourceMetadata;
import me.lucko.spark.common.sampler.window.ProtoTimeEncoder;
import me.lucko.spark.common.sampler.window.WindowStatisticsCollector;
import me.lucko.spark.common.util.classfinder.ClassFinder;
import me.lucko.spark.common.ws.ViewerSocket;
import me.lucko.spark.proto.SparkProtos;
import me.lucko.spark.proto.SparkSamplerProtos.SamplerData;
Expand All @@ -44,6 +45,7 @@
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Supplier;

/**
* Base implementation class for {@link Sampler}s.
Expand Down Expand Up @@ -230,11 +232,11 @@ protected void writeMetadataToProto(SamplerData.Builder proto, SparkPlatform pla
proto.setMetadata(metadata);
}

protected void writeDataToProto(SamplerData.Builder proto, DataAggregator dataAggregator, MergeMode mergeMode, ClassSourceLookup classSourceLookup) {
protected void writeDataToProto(SamplerData.Builder proto, DataAggregator dataAggregator, MergeMode mergeMode, ClassSourceLookup classSourceLookup, Supplier<ClassFinder> classFinderSupplier) {
List<ThreadNode> data = dataAggregator.exportData();
data.sort(Comparator.comparing(ThreadNode::getThreadLabel));

ClassSourceLookup.Visitor classSourceVisitor = ClassSourceLookup.createVisitor(classSourceLookup);
ClassSourceLookup.Visitor classSourceVisitor = ClassSourceLookup.createVisitor(classSourceLookup, classFinderSupplier);

ProtoTimeEncoder timeEncoder = new ProtoTimeEncoder(getMode().valueTransformer(), data);
int[] timeWindows = timeEncoder.getKeys();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ public SamplerData toProto(SparkPlatform platform, ExportProps exportProps) {
proto.setChannelInfo(exportProps.channelInfo());
}
writeMetadataToProto(proto, platform, exportProps.creator(), exportProps.comment(), this.dataAggregator);
writeDataToProto(proto, this.dataAggregator, exportProps.mergeMode().get(), exportProps.classSourceLookup().get());
writeDataToProto(proto, this.dataAggregator, exportProps.mergeMode().get(), exportProps.classSourceLookup().get(), platform::createClassFinder);
return proto.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ public SamplerData toProto(SparkPlatform platform, ExportProps exportProps) {
proto.setChannelInfo(exportProps.channelInfo());
}
writeMetadataToProto(proto, platform, exportProps.creator(), exportProps.comment(), this.dataAggregator);
writeDataToProto(proto, this.dataAggregator, exportProps.mergeMode().get(), exportProps.classSourceLookup().get());
writeDataToProto(proto, this.dataAggregator, exportProps.mergeMode().get(), exportProps.classSourceLookup().get(), platform::createClassFinder);
return proto.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import me.lucko.spark.common.SparkPlatform;
import me.lucko.spark.common.sampler.node.StackTraceNode;
import me.lucko.spark.common.sampler.node.ThreadNode;
import me.lucko.spark.common.util.ClassFinder;
import me.lucko.spark.common.util.classfinder.ClassFinder;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.io.IOException;
Expand All @@ -42,6 +42,7 @@
import java.util.Objects;
import java.util.Queue;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
Expand Down Expand Up @@ -203,11 +204,11 @@ interface Visitor {
Map<String, String> getLineSourceMapping();
}

static Visitor createVisitor(ClassSourceLookup lookup) {
static Visitor createVisitor(ClassSourceLookup lookup, Supplier<ClassFinder> classFinderSupplier) {
if (lookup == ClassSourceLookup.NO_OP) {
return NoOpVisitor.INSTANCE; // don't bother!
}
return new VisitorImpl(lookup);
return new VisitorImpl(lookup, classFinderSupplier.get());
}

enum NoOpVisitor implements Visitor {
Expand Down Expand Up @@ -254,14 +255,15 @@ public Map<String, String> getLineSourceMapping() {
*/
class VisitorImpl implements Visitor {
private final ClassSourceLookup lookup;
private final ClassFinder classFinder = new ClassFinder();
private final ClassFinder classFinder;

private final SourcesMap<String> classSources = new SourcesMap<>(Function.identity());
private final SourcesMap<MethodCall> methodSources = new SourcesMap<>(MethodCall::toString);
private final SourcesMap<MethodCallByLine> lineSources = new SourcesMap<>(MethodCallByLine::toString);

VisitorImpl(ClassSourceLookup lookup) {
VisitorImpl(ClassSourceLookup lookup, ClassFinder classFinder) {
this.lookup = lookup;
this.classFinder = classFinder;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ListMultimap;
import me.lucko.spark.common.sampler.node.StackTraceNode;
import me.lucko.spark.common.util.classfinder.ClassFinder;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
Expand All @@ -43,8 +44,13 @@
* to a method (method name + method description).
*/
public final class MethodDisambiguator {
private final Map<String, ComputedClass> cache = new ConcurrentHashMap<>();
private final ClassFinder classFinder = new ClassFinder();
private final ClassFinder classFinder;
private final Map<String, ComputedClass> cache;

public MethodDisambiguator(ClassFinder classFinder) {
this.classFinder = classFinder;
this.cache = new ConcurrentHashMap<>();
}

public Optional<MethodDescription> disambiguate(StackTraceNode element) {
String desc = element.getMethodDescription();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* This file is part of spark.
*
* Copyright (c) lucko (Luck) <[email protected]>
* Copyright (c) contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package me.lucko.spark.common.util.classfinder;

import com.google.common.collect.ImmutableList;
import org.checkerframework.checker.nullness.qual.Nullable;

public interface ClassFinder {

/**
* Creates a ClassFinder that combines the results of multiple other finders.
*
* @param finders the other class finders
* @return the combined class finder
*/
static ClassFinder combining(ClassFinder... finders) {
return new CombinedClassFinder(ImmutableList.copyOf(finders));
}

/**
* Attempts to find a class by name.
*
* @param className the name of the class
* @return the class, if found
*/
@Nullable Class<?> findClass(String className);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* This file is part of spark.
*
* Copyright (c) lucko (Luck) <[email protected]>
* Copyright (c) contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package me.lucko.spark.common.util.classfinder;

import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.List;

class CombinedClassFinder implements ClassFinder {
private final List<ClassFinder> finders;

CombinedClassFinder(List<ClassFinder> finders) {
this.finders = finders;
}

@Override
public @Nullable Class<?> findClass(String className) {
for (ClassFinder finder : this.finders) {
Class<?> clazz = finder.findClass(className);
if (clazz != null) {
return clazz;
}
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* This file is part of spark.
*
* Copyright (c) lucko (Luck) <[email protected]>
* Copyright (c) contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package me.lucko.spark.common.util.classfinder;

import org.checkerframework.checker.nullness.qual.Nullable;

/**
* Uses {@link Class#forName(String)} to find a class reference for given class names.
*/
public enum FallbackClassFinder implements ClassFinder {
INSTANCE;

@Override
public @Nullable Class<?> findClass(String className) {
try {
return Class.forName(className);
} catch (Throwable e) {
return null;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package me.lucko.spark.common.util;
package me.lucko.spark.common.util.classfinder;

import me.lucko.spark.common.SparkPlugin;
import me.lucko.spark.common.util.JavaVersion;
import net.bytebuddy.agent.ByteBuddyAgent;
import org.checkerframework.checker.nullness.qual.Nullable;

Expand All @@ -33,18 +35,18 @@
*
* <p>This is necessary as we don't always have access to the classloader for a given class.</p>
*/
public class ClassFinder {
public class InstrumentationClassFinder implements ClassFinder {

private static boolean warned = false;

private static Instrumentation loadInstrumentation() {
private static Instrumentation loadInstrumentation(SparkPlugin plugin) {
Instrumentation instrumentation = null;
try {
instrumentation = ByteBuddyAgent.install();
if (!warned && JavaVersion.getJavaVersion() >= 21) {
warned = true;
SparkStaticLogger.log(Level.INFO, "If you see a warning above that says \"WARNING: A Java agent has been loaded dynamically\", it can be safely ignored.");
SparkStaticLogger.log(Level.INFO, "See here for more information: https://spark.lucko.me/docs/misc/Java-agent-warning");
plugin.log(Level.INFO, "If you see a warning above that says \"WARNING: A Java agent has been loaded dynamically\", it can be safely ignored.");
plugin.log(Level.INFO, "See here for more information: https://spark.lucko.me/docs/misc/Java-agent-warning");
}
} catch (Exception e) {
// ignored
Expand All @@ -54,8 +56,8 @@ private static Instrumentation loadInstrumentation() {

private final Map<String, Class<?>> classes = new HashMap<>();

public ClassFinder() {
Instrumentation instrumentation = loadInstrumentation();
public InstrumentationClassFinder(SparkPlugin plugin) {
Instrumentation instrumentation = loadInstrumentation(plugin);
if (instrumentation == null) {
return;
}
Expand All @@ -66,21 +68,9 @@ public ClassFinder() {
}
}

@Override
public @Nullable Class<?> findClass(String className) {
// try instrumentation
Class<?> clazz = this.classes.get(className);
if (clazz != null) {
return clazz;
}

// try Class.forName
try {
return Class.forName(className);
} catch (Throwable e) {
// ignore
}

return null;
return this.classes.get(className);
}

}
Loading

0 comments on commit ed8eac5

Please sign in to comment.