Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Classfile integration #1300

Merged
merged 10 commits into from
Feb 2, 2025
2 changes: 0 additions & 2 deletions cli-impl/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
requires aya.md;
requires aya.producer;
requires aya.compiler;
requires java.compiler;
requires jdk.compiler;
requires aya.jb.md;
requires org.jetbrains.annotations;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.cli.library.incremental;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;

import kala.collection.immutable.ImmutableSeq;
import kala.collection.mutable.MutableList;
import org.aya.cli.library.source.LibraryOwner;
Expand All @@ -10,7 +17,6 @@
import org.aya.compiler.CompiledModule;
import org.aya.compiler.serializers.ModuleSerializer;
import org.aya.compiler.serializers.NameSerializer;
import org.aya.prelude.GeneratedVersion;
import org.aya.primitive.PrimFactory;
import org.aya.resolve.ResolveInfo;
import org.aya.resolve.context.EmptyContext;
Expand All @@ -20,23 +26,10 @@
import org.aya.syntax.ref.ModulePath;
import org.aya.syntax.ref.QPath;
import org.aya.util.FileUtil;
import org.aya.util.error.Global;
import org.aya.util.reporter.Reporter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.tools.ToolProvider;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

public class DiskCompilerAdvisor implements CompilerAdvisor {
private static class AyaClassLoader extends URLClassLoader {
public MutableList<Path> urls = MutableList.create();
Expand Down Expand Up @@ -133,32 +126,7 @@ public void addURL(Path url) throws MalformedURLException {
QPath.fileLevel(file.moduleName()),
defs.filterIsInstance(TopLevelDef.class)));
var libraryRoot = file.owner().outDir();
var baseDir = computeBaseDir(libraryRoot).toAbsolutePath();
var relativePath = NameSerializer.getReference(QPath.fileLevel(file.moduleName()), null,
NameSerializer.NameType.ClassPath) + ".java";
var javaSrcPath = baseDir.resolve(relativePath);
FileUtil.writeString(javaSrcPath, javaCode);
var compiler = ToolProvider.getSystemJavaCompiler();
var fileManager = compiler.getStandardFileManager(null, null, StandardCharsets.UTF_8);
var compilationUnits = fileManager.getJavaFileObjects(javaSrcPath);
var classpath = cl.urls.view()
.appended(baseDir)
.map(Path::toString);
var selfClassPath = System.getProperty("java.class.path");
if (selfClassPath != null && !selfClassPath.isBlank()) classpath = classpath.appended(selfClassPath);
else {
// here, I'm in jlink mode
var jlinkClassPath = Paths.get(System.getProperty("jdk.module.path"))
.resolveSibling("misc")
.resolve("syntax-fat.jar")
.normalize();
classpath = classpath.appended(jlinkClassPath.toString());
}
var options = List.of("--class-path", classpath.joinToString(File.pathSeparator),
"--enable-preview", "--release", GeneratedVersion.JDK_VERSION);
var task = compiler.getTask(null, fileManager, null, options, null, compilationUnits);
boolean compileSuccess = task.call();
if (Global.DELETE_JIT_JAVA_SOURCE && compileSuccess) Files.delete(javaSrcPath);
javaCode.writeTo(computeBaseDir(libraryRoot).toAbsolutePath());
var coreFile = file.compiledCorePath();

// save compiled core and load compiled ResolveInfo
Expand Down
22 changes: 10 additions & 12 deletions cli-impl/src/test/java/org/aya/test/LibraryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.test;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;

import static org.junit.jupiter.api.Assertions.assertEquals;

import kala.collection.SeqView;
import kala.collection.immutable.ImmutableSeq;
import kala.collection.mutable.MutableSet;
Expand All @@ -19,23 +29,12 @@
import org.aya.prettier.AyaPrettierOptions;
import org.aya.primitive.PrimFactory;
import org.aya.util.FileUtil;
import org.aya.util.error.Global;
import org.aya.util.reporter.ThrowingReporter;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;

import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* LibraryTest testing the compilation of a library and its dependencies
*
Expand All @@ -62,7 +61,6 @@ public void testOnDisk(@NotNull String libName) throws IOException {

// Use this test for additional compilation
public static void main(String... args) throws IOException {
Global.DELETE_JIT_JAVA_SOURCE = false;
assertEquals(0, compile(DIR));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang.
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.compiler.free.morphism.asm;
package org.aya.compiler;

import java.io.IOException;
import java.lang.constant.ClassDesc;
Expand Down Expand Up @@ -36,8 +36,8 @@ record Default(@NotNull MutableMap<Path, byte[]> output) implements AsmOutputCol
public void writeTo(@NotNull Path baseDir) throws IOException {
output.forEachChecked(((path, bytes) -> {
var filePath = baseDir.resolve(path);
filePath.getParent().toFile().mkdirs();
Files.write(baseDir.resolve(path), bytes);
Files.createDirectories(filePath.getParent());
Files.write(filePath, bytes);
}));
}
}
Expand Down
21 changes: 8 additions & 13 deletions jit-compiler/src/main/java/org/aya/compiler/SourceBuilder.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang.
// Copyright (c) 2020-2025 Tesla (Yinsen) Zhang.
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.compiler;

import kala.collection.immutable.ImmutableSeq;
import kala.collection.immutable.primitive.ImmutableIntSeq;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.function.Consumer;
import java.util.function.IntConsumer;

import static org.aya.compiler.serializers.AyaSerializer.CLASS_PANIC;
import static org.aya.compiler.serializers.ExprializeUtil.makeString;

import kala.collection.immutable.ImmutableSeq;
import kala.collection.immutable.primitive.ImmutableIntSeq;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public final class SourceBuilder {
public final @NotNull StringBuilder builder;
public final @NotNull NameGenerator nameGen;
Expand All @@ -27,10 +27,7 @@ public SourceBuilder() {
}

public record JitParam(@NotNull String name, @NotNull String type) { }

private void assertLineBegin() {
assert isLineBegin;
}
private void assertLineBegin() { assert isLineBegin; }

public void runInside(@NotNull Runnable runnable) {
indent++;
Expand All @@ -39,9 +36,7 @@ public void runInside(@NotNull Runnable runnable) {
}


public int indent() {
return this.indent;
}
public int indent() { return this.indent; }

private void fillIndent() {
assertLineBegin();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import java.lang.constant.*;
import java.lang.invoke.LambdaMetafactory;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
Expand All @@ -13,6 +14,7 @@
import kala.collection.mutable.MutableList;
import kala.collection.mutable.MutableMap;
import kala.value.LazyValue;
import org.aya.compiler.AsmOutputCollector;
import org.aya.compiler.free.*;
import org.aya.compiler.free.data.FieldRef;
import org.aya.compiler.free.data.MethodRef;
Expand All @@ -21,31 +23,30 @@
import org.glavo.classfile.AccessFlag;
import org.glavo.classfile.AccessFlags;
import org.glavo.classfile.ClassBuilder;
import org.glavo.classfile.attribute.InnerClassInfo;
import org.glavo.classfile.attribute.InnerClassesAttribute;
import org.glavo.classfile.attribute.NestMembersAttribute;
import org.glavo.classfile.constantpool.InvokeDynamicEntry;
import org.glavo.classfile.constantpool.MethodHandleEntry;
import org.jetbrains.annotations.NotNull;

public final class AsmClassBuilder implements FreeClassBuilder {
public final @NotNull ClassDesc owner;
public final @NotNull ClassDesc ownerSuper;
public final @NotNull ClassBuilder writer; // I am sorry
public final @NotNull ClassData classData;
public final @NotNull ClassBuilder writer;
public final @NotNull AsmOutputCollector collector;
public final @NotNull MutableList<ClassDesc> nestedMembers = MutableList.create();
public final @NotNull MutableList<String> nestedMembers = MutableList.create();
public final @NotNull MutableMap<FieldRef, Function<FreeExprBuilder, FreeJavaExpr>> fieldInitializers = MutableLinkedHashMap.of();
private int lambdaCounter = 0;

/// @see java.lang.invoke.LambdaMetafactory#metafactory
private final @NotNull LazyValue<MethodHandleEntry> lambdaBoostrapMethodHandle;

public AsmClassBuilder(
@NotNull ClassDesc owner,
@NotNull ClassDesc ownerSuper,
@NotNull ClassData classData,
@NotNull ClassBuilder writer,
@NotNull AsmOutputCollector collector
) {
this.owner = owner;
this.ownerSuper = ownerSuper;
this.classData = classData;
this.writer = writer;
this.collector = collector;
this.lambdaBoostrapMethodHandle = LazyValue.of(() -> writer.constantPool().methodHandleEntry(MethodHandleDesc.ofMethod(
Expand All @@ -64,10 +65,21 @@ public AsmClassBuilder(
)));
}

public @NotNull ClassDesc owner() {
return classData.className();
}

public @NotNull ClassDesc ownerSuper() {
return classData.classSuper();
}

@Override
public void buildNestedClass(@NotNull CompiledAya compiledAya, @NotNull String name, @NotNull Class<?> superclass, @NotNull Consumer<FreeClassBuilder> builder) {
var className = AsmJavaBuilder.buildClass(collector, compiledAya, owner, name, FreeUtil.fromClass(superclass), builder);
nestedMembers.append(className);
AsmJavaBuilder.buildClass(collector, compiledAya,
new ClassData(owner().nested(name), FreeUtil.fromClass(superclass),
new ClassData.Outer(classData, name)),
builder);
nestedMembers.append(name);
}

public @NotNull MethodRef buildMethod(
Expand All @@ -86,7 +98,7 @@ public void buildNestedClass(@NotNull CompiledAya compiledAya, @NotNull String n
});
});

return new MethodRef(owner, name, returnType, paramTypes, false);
return new MethodRef(owner(), name, returnType, paramTypes, false);
}

@Override public @NotNull MethodRef buildMethod(
Expand All @@ -110,7 +122,7 @@ public void buildNestedClass(@NotNull CompiledAya compiledAya, @NotNull String n
public @NotNull FieldRef buildConstantField(@NotNull ClassDesc returnType, @NotNull String name, @NotNull Function<FreeExprBuilder, FreeJavaExpr> initializer) {
writer.withField(name, returnType, AccessFlags.ofField(AccessFlag.PUBLIC, AccessFlag.STATIC, AccessFlag.FINAL).flagsMask());

var ref = new FieldRef(owner, returnType, name);
var ref = new FieldRef(owner(), returnType, name);
fieldInitializers.put(ref, initializer);
return ref;
}
Expand All @@ -137,7 +149,7 @@ public void buildNestedClass(@NotNull CompiledAya compiledAya, @NotNull String n
// the method handle to the static lambda method
var lambdaMethodHandle = MethodHandleDesc.ofMethod(
DirectMethodHandleDesc.Kind.STATIC,
owner,
owner(),
lambdaMethodName,
lambdaMethodDesc
);
Expand All @@ -159,9 +171,23 @@ public void buildNestedClass(@NotNull CompiledAya compiledAya, @NotNull String n
}

public void postBuild() {
ImmutableSeq<InnerClassInfo> innerClassesEntries;
var outerClassData = classData.outer();
if (outerClassData == null) {
innerClassesEntries = nestedMembers.map(cd ->
InnerClassInfo.of(owner().nested(cd), Optional.of(owner()), Optional.of(cd), ClassData.AF_NESTED));
} else {
assert nestedMembers.isEmpty();
innerClassesEntries = ImmutableSeq.of(InnerClassInfo.of(owner(), Optional.of(outerClassData.data().classSuper()), Optional.of(outerClassData.thisName()), ClassData.AF_NESTED));
}

if (innerClassesEntries.isNotEmpty()) {
writer.with(InnerClassesAttribute.of(innerClassesEntries.asJava()));
}

if (nestedMembers.isNotEmpty()) {
var pool = writer.constantPool();
writer.with(NestMembersAttribute.of(nestedMembers.map(pool::classEntry).asJava()));
writer.with(NestMembersAttribute.of(nestedMembers.map(t -> pool.classEntry(owner().nested(t))).asJava()));
}

if (fieldInitializers.isNotEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public void subscoped(@NotNull CodeBuilder innerWrite, @NotNull Consumer<AsmCode
invokeSuperCon(@NotNull ImmutableSeq<ClassDesc> superConParams, @NotNull ImmutableSeq<FreeJavaExpr> superConArgs) {
invoke(
InvokeKind.Special,
FreeJavaResolver.resolve(parent.ownerSuper, ConstantDescs.INIT_NAME, ConstantDescs.CD_void, superConParams, false),
FreeJavaResolver.resolve(parent.ownerSuper(), ConstantDescs.INIT_NAME, ConstantDescs.CD_void, superConParams, false),
thisRef(),
superConArgs);
}
Expand Down Expand Up @@ -119,8 +119,8 @@ public void ifInstanceOf(@NotNull FreeJavaExpr lhs, @NotNull ClassDesc rhs, @Not
lhsExpr.accept(this);
writer.instanceof_(rhs);
ifThenElse(Opcode.IFNE, builder -> {
var cast = checkcast(lhs, rhs);
var bind = makeVar(rhs, cast);
var cast = builder.checkcast(lhs, rhs);
var bind = builder.makeVar(rhs, cast);
thenBlock.accept(builder, bind);
}, elseBlock);
}
Expand Down Expand Up @@ -310,7 +310,7 @@ public void invoke(

@Override public @NotNull AsmExpr thisRef() {
assert hasThis;
return AsmExpr.withType(parent.owner, builder -> builder.writer.aload(0));
return AsmExpr.withType(parent.owner(), builder -> builder.writer.aload(0));
}

@Override
Expand Down
Loading
Loading