Skip to content

Commit

Permalink
Merge pull request #14 from Over-Run/feature
Browse files Browse the repository at this point in the history
  • Loading branch information
squid233 authored May 17, 2024
2 parents d7d4983 + a20cacf commit e06a0d6
Show file tree
Hide file tree
Showing 11 changed files with 960 additions and 398 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ Import as a Gradle dependency:

```groovy
dependencies {
implementation("io.github.over-run:marshal:0.1.0-alpha.25-jdk22")
implementation("io.github.over-run:marshal:0.1.0-alpha.26-jdk22")
}
```

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ projGroupId=io.github.over-run
projArtifactId=marshal
# The project name should only contain lowercase letters, numbers and hyphen.
projName=marshal
projVersion=0.1.0-alpha.25-jdk22
projVersion=0.1.0-alpha.26-jdk22
projDesc=Marshaler of native libraries
# Uncomment them if you want to publish to maven repository.
projUrl=https://github.com/Over-Run/marshal
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
module io.github.overrun.marshal {
exports overrun.marshal;
exports overrun.marshal.gen;
exports overrun.marshal.gen.processor;
exports overrun.marshal.struct;

opens overrun.marshal.internal.data;

requires static org.jetbrains.annotations;
requires jdk.jshell;
}
696 changes: 301 additions & 395 deletions src/main/java/overrun/marshal/Downcall.java

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/main/java/overrun/marshal/gen/Convert.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
import java.lang.annotation.*;

/**
* Marks an element that needs to convert from {@code boolean} to the given type.
* Marks a parameter that needs to convert from {@code boolean} to the given type,
* or a return type that needs to convert from the given type to {@code boolean}.
* <p>
* The type of the marked element must be {@code boolean}; otherwise this annotation will be ignored.
* <h2>Example</h2>
Expand Down
148 changes: 148 additions & 0 deletions src/main/java/overrun/marshal/gen/processor/ArgumentProcessor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* MIT License
*
* Copyright (c) 2024 Overrun Organization
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*/

package overrun.marshal.gen.processor;

import overrun.marshal.gen.Type;
import overrun.marshal.internal.StringCharset;

import java.lang.classfile.CodeBuilder;
import java.lang.constant.MethodTypeDesc;
import java.util.ArrayList;
import java.util.List;

import static java.lang.constant.ConstantDescs.CD_boolean;
import static overrun.marshal.internal.Constants.*;

/**
* Method argument processor
*
* @author squid233
* @since 0.1.0
*/
public final class ArgumentProcessor implements Processor<ProcessorType, ArgumentProcessorContext> {
private static final ArgumentProcessor INSTANCE = new ArgumentProcessor();
private final List<Processor<ProcessorType, ArgumentProcessorContext>> list = new ArrayList<>(0);

private ArgumentProcessor() {
}

@SuppressWarnings("preview")
public boolean process(CodeBuilder builder, ProcessorType type, ArgumentProcessorContext context) {
switch (type) {
case ProcessorType.Value value -> {
if (value == ProcessorType.Value.BOOLEAN &&
context.convert() != null) {
final Type convertType = context.convert().value();
builder.loadInstruction(
value.typeKind(),
context.parameterSlot()
).invokestatic(CD_Marshal,
marshalFromBooleanMethod(convertType),
MethodTypeDesc.of(convertType.classDesc(), CD_boolean));
} else {
builder.loadInstruction(
value.typeKind().asLoadable(),
context.parameterSlot()
);
}
}
case ProcessorType.Allocator _ -> builder.aload(context.parameterSlot());
case ProcessorType.Str _ -> {
builder.aload(context.allocatorSlot())
.aload(context.parameterSlot());
if (StringCharset.getCharset(builder, context.parameter())) {
builder.invokestatic(CD_Marshal,
"marshal",
MTD_MemorySegment_SegmentAllocator_String_Charset);
} else {
builder.invokestatic(CD_Marshal,
"marshal",
MTD_MemorySegment_SegmentAllocator_String);
}
}
case ProcessorType.Addr _, ProcessorType.CEnum _ -> builder
.aload(context.parameterSlot())
.invokestatic(CD_Marshal,
"marshal",
MethodTypeDesc.of(type.downcallClassDesc(), type.marshalClassDesc()));
case ProcessorType.Upcall _ -> builder
.aload(context.allocatorSlot())
.checkcast(CD_Arena)
.aload(context.parameterSlot())
.invokestatic(CD_Marshal,
"marshal",
MTD_MemorySegment_Arena_Upcall);
case ProcessorType.Array array -> {
final ProcessorType componentType = array.componentType();
final boolean isStringArray = componentType instanceof ProcessorType.Str;
final boolean isUpcallArray = componentType instanceof ProcessorType.Upcall;
builder.aload(context.allocatorSlot());
if (isUpcallArray) {
builder.checkcast(CD_Arena);
}
builder.aload(context.parameterSlot());
if (isStringArray && StringCharset.getCharset(builder, context.parameter())) {
builder.invokestatic(CD_Marshal,
"marshal",
MTD_MemorySegment_SegmentAllocator_StringArray_Charset);
} else {
builder.invokestatic(CD_Marshal,
"marshal",
MethodTypeDesc.of(CD_MemorySegment,
isUpcallArray ? CD_Arena : CD_SegmentAllocator,
array.marshalClassDesc()));
}
}
default -> {
for (var processor : list) {
if (!processor.process(builder, type, context)) {
break;
}
}
}
}
return false;
}

/**
* Registers a processor
*
* @param processor the processor
*/
public void registerProcessor(Processor<ProcessorType, ArgumentProcessorContext> processor) {
list.add(processor);
}

/**
* {@return this}
*/
public static ArgumentProcessor getInstance() {
return INSTANCE;
}

private static String marshalFromBooleanMethod(Type convertType) {
return switch (convertType) {
case CHAR -> "marshalAsChar";
case BYTE -> "marshalAsByte";
case SHORT -> "marshalAsShort";
case INT -> "marshalAsInt";
case LONG -> "marshalAsLong";
case FLOAT -> "marshalAsFloat";
case DOUBLE -> "marshalAsDouble";
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* MIT License
*
* Copyright (c) 2024 Overrun Organization
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*/

package overrun.marshal.gen.processor;

import overrun.marshal.gen.Convert;

import java.lang.reflect.Parameter;

/**
* The argument processor context
*
* @param parameter parameter
* @param parameterSlot parameter slot
* @param allocatorSlot allocator slot
* @param convert boolean convert
* @author squid233
* @since 0.1.0
*/
public record ArgumentProcessorContext(
Parameter parameter,
int parameterSlot,
int allocatorSlot,
Convert convert
) {
}
39 changes: 39 additions & 0 deletions src/main/java/overrun/marshal/gen/processor/Processor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* MIT License
*
* Copyright (c) 2024 Overrun Organization
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*/

package overrun.marshal.gen.processor;

import java.lang.classfile.CodeBuilder;

/**
* Processor
*
* @param <T> target type
* @param <C> context type
* @author squid233
* @since 0.1.0
*/
public interface Processor<T, C> {
/**
* Processes with the context
*
* @param builder the code builder
* @param type the type
* @param context the context
* @return {@code true} if should continue; {@code false} otherwise
*/
boolean process(CodeBuilder builder, T type, C context);
}
Loading

0 comments on commit e06a0d6

Please sign in to comment.