Skip to content

Commit

Permalink
merge: Classfile integration (#1300)
Browse files Browse the repository at this point in the history
Followup #1297
  • Loading branch information
ice1000 authored Feb 2, 2025
2 parents 171c6ff + 963ef40 commit 7d1ffdc
Show file tree
Hide file tree
Showing 19 changed files with 204 additions and 251 deletions.
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

0 comments on commit 7d1ffdc

Please sign in to comment.