This is an automated email from the ASF dual-hosted git repository. amashenkov pushed a commit to branch ignite-13618-javapoet in repository https://gitbox.apache.org/repos/asf/ignite-3.git
commit b3223bfd05fb9d9fa48098d823df787d8d10212a Author: Andrew Mashenkov <andrey.mashen...@gmail.com> AuthorDate: Sat Dec 12 22:19:31 2020 +0300 wip. rewrite codegen with javapoet --- modules/commons/pom.xml | 7 +- .../internal/schema/marshaller/MarshallerUtil.java | 11 +- .../IdentityObjectMarshallerExprGenerator.java | 22 +- .../generator/JaninoSerializerGenerator.java | 289 ++++++++++++++++++--- .../generator/MarshallerExprGenerator.java | 28 +- .../marshaller/generator/TupleAccessorExpr.java | 158 +++++++++++ .../marshaller/reflection/FieldAccessor.java | 4 +- .../apache/ignite/internal/util/ObjectFactory.java | 26 +- pom.xml | 1 + 9 files changed, 485 insertions(+), 61 deletions(-) diff --git a/modules/commons/pom.xml b/modules/commons/pom.xml index 05a2fff..a5b64e8 100644 --- a/modules/commons/pom.xml +++ b/modules/commons/pom.xml @@ -43,12 +43,11 @@ <version>${jetbrains.annotations.version}</version> </dependency> <dependency> - <groupId>org.codehaus.janino</groupId> - <artifactId>janino</artifactId> - <version>${janino.version}</version> + <groupId>com.squareup</groupId> + <artifactId>javapoet</artifactId> + <version>${javapoet.version}</version> </dependency> - <!-- Test dependencies --> <dependency> <groupId>org.junit.jupiter</groupId> diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java index c111ba8..f43f9b5 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java @@ -21,6 +21,7 @@ import java.util.BitSet; import java.util.UUID; import org.apache.ignite.internal.schema.NativeType; import org.apache.ignite.internal.schema.TupleAssembler; +import org.apache.ignite.internal.util.ObjectFactory; /** * Marshaller utility class. @@ -96,8 +97,16 @@ public final class MarshallerUtil { return null; } + public static <T> ObjectFactory<T> factoryForClass(Class<T> type) { + if (mode(type) == null) + return new ObjectFactory<>(type); + else + return null; + } + /** * Stub. */ - private MarshallerUtil() {} + private MarshallerUtil() { + } } diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java index e574e61..f86bc0b 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal.schema.marshaller.generator; +import com.squareup.javapoet.CodeBlock; import org.apache.ignite.internal.schema.marshaller.Serializer; /** @@ -27,9 +28,16 @@ class IdentityObjectMarshallerExprGenerator extends MarshallerExprGenerator { * Constructor. * * @param accessor Object field access expression generators. + * @param tupleAccessorGen */ - IdentityObjectMarshallerExprGenerator(FieldAccessExprGenerator accessor) { - super(null /* no instantiation needed */, new FieldAccessExprGenerator[] {accessor}); + IdentityObjectMarshallerExprGenerator(FieldAccessExprGenerator accessor, + TupleAccessorExpr tupleAccessorGen) { + super( + null /* no instantiation needed */, + new FieldAccessExprGenerator[] {accessor}, + new TupleAccessorExpr[] {tupleAccessorGen} + ); + } /** {@inheritDoc} */ @@ -42,4 +50,14 @@ class IdentityObjectMarshallerExprGenerator extends MarshallerExprGenerator { @Override public void appendUnmarshallObjectExpr(StringBuilder sb, String indent) { sb.append(indent).append("Object obj = ").append(accessors[0].readColumnExpr()).append(";" + JaninoSerializerGenerator.LF); } + + @Override public CodeBlock unmarshallObjectCode(String tupleExpr) { + return CodeBlock.builder() + .add("return ").addStatement(tupleAccessors[0].read(tupleExpr)) + .build(); + } + + @Override public CodeBlock marshallObjectCode(String asm, String objVar) { + return tupleAccessors[0].write(asm, objVar); + } } diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java index 654bf97..a45a8be 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java @@ -17,23 +17,53 @@ package org.apache.ignite.internal.schema.marshaller.generator; +import com.squareup.javapoet.AnnotationSpec; +import com.squareup.javapoet.ArrayTypeName; +import com.squareup.javapoet.CodeBlock; +import com.squareup.javapoet.JavaFile; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import java.lang.invoke.VarHandle; import java.lang.reflect.Constructor; import java.lang.reflect.Field; +import java.util.HashMap; +import javax.annotation.processing.Generated; +import javax.lang.model.element.Modifier; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileManager; +import javax.tools.ToolProvider; +import org.apache.ignite.internal.schema.ByteBufferTuple; import org.apache.ignite.internal.schema.Columns; import org.apache.ignite.internal.schema.SchemaDescriptor; +import org.apache.ignite.internal.schema.Tuple; +import org.apache.ignite.internal.schema.TupleAssembler; import org.apache.ignite.internal.schema.marshaller.BinaryMode; import org.apache.ignite.internal.schema.marshaller.MarshallerUtil; +import org.apache.ignite.internal.schema.marshaller.SerializationException; import org.apache.ignite.internal.schema.marshaller.Serializer; import org.apache.ignite.internal.schema.marshaller.SerializerFactory; -import org.apache.ignite.internal.util.IgniteUnsafeUtils; -import org.codehaus.commons.compiler.CompilerFactoryFactory; +import org.apache.ignite.internal.util.ObjectFactory; import org.codehaus.commons.compiler.IClassBodyEvaluator; +import org.codehaus.janino.ClassLoaderIClassLoader; +import org.codehaus.janino.Compiler; +import org.codehaus.janino.util.ResourceFinderClassLoader; +import org.codehaus.janino.util.resource.MapResourceCreator; +import org.codehaus.janino.util.resource.MapResourceFinder; +import org.codehaus.janino.util.resource.Resource; +import org.codehaus.janino.util.resource.StringResource; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** * {@link Serializer} code generator backed with Janino. */ public class JaninoSerializerGenerator implements SerializerFactory { + + public static final String SERIALIZER_PACKAGE_NAME = "org.apache.ignite.internal.schema.marshaller"; + + public static final String SERIALIZER_CLASS_NAME_PREFIX = "JaninoSerializerForSchema_"; + /** Tabulate. */ static final String TAB = " "; @@ -52,38 +82,106 @@ public class JaninoSerializerGenerator implements SerializerFactory { Class<?> keyClass, Class<?> valClass ) { - try { - final IClassBodyEvaluator ce = CompilerFactoryFactory.getDefaultCompilerFactory().newClassBodyEvaluator(); + // Generate Serializer code. + final String className = SERIALIZER_CLASS_NAME_PREFIX + schema.version(); - // Generate Serializer code. - String code = generateSerializerClassCode(ce, schema, keyClass, valClass); + String code = generateSerializerClassCode(className, schema, keyClass, valClass); - //TODO: pass code to logger on trace level. + //TODO: pass code to logger on trace level. - if (enabledDebug) { - ce.setDebuggingInformation(true, true, true); + final HashMap<String, byte[]> classes = new HashMap<>(); + final Compiler cmp = new Compiler( + new MapResourceFinder(classes), + new ClassLoaderIClassLoader(getClass().getClassLoader()) + ); - //TODO: dump code to log. -// System.out.println(code); - } + cmp.setClassFileCreator(new MapResourceCreator(classes)); - try { // Compile and load class. - ce.setParentClassLoader(getClass().getClassLoader()); - ce.cook(code); + if (enabledDebug) { + cmp.setDebugSource(true); + cmp.setDebugLines(true); + cmp.setDebugVars(true); + cmp.setVerbose(true); - // Create and return Serializer instance. - final Constructor<Serializer> ctor = (Constructor<Serializer>)ce.getClazz() - .getDeclaredConstructor(schema.getClass(), Class.class, Class.class); + System.out.print(code); + } - return ctor.newInstance(schema, keyClass, valClass); - } - catch (Exception ex) { - if (enabledDebug) - throw new IllegalStateException("Failed to compile/instantiate generated Serializer: code=" + - LF + code + LF, ex); - else - throw new IllegalStateException("Failed to compile/instantiate generated Serializer.", ex); - } + try { // Compile code. + cmp.compile(new Resource[] { + new StringResource("file", code)}); + + ClassLoader cl = new ResourceFinderClassLoader( + new MapResourceFinder(classes), + getClass().getClassLoader() + ); + + // Load class and create instance. + final Class<?> aClass = cl.loadClass(SERIALIZER_PACKAGE_NAME + '.' + className); + + final Constructor<Serializer> ctor = (Constructor<Serializer>)aClass + .getDeclaredConstructor(schema.getClass(), Class.class, Class.class); + + return ctor.newInstance(schema, keyClass, valClass); + } + catch (Throwable ex) { + if (enabledDebug) + throw new IllegalStateException("Failed to compile generated Serializer code:\n" + code, ex); + else + throw new IllegalStateException("Failed to compile/instantiate generated Serializer.", ex); + } + } + + /** + * Generates serializer code. + * + * @param className Serializer class name. + * @param valClass Value class. + * @return Generated class code. + */ + private String generateSerializerClassCode(String className, SchemaDescriptor schema, Class<?> keyClass, + Class<?> valClass) { + try { + final StringBuilder sb = new StringBuilder(); + + // Build field accessor generators. + final MarshallerExprGenerator keyMarsh = createObjectMarshaller(valClass, "valFactory", schema.valueColumns(), schema.keyColumns().length()); + final MarshallerExprGenerator valMarsh = createObjectMarshaller(valClass, "valFactory", schema.valueColumns(), schema.keyColumns().length()); + + JavaFile + .builder( + SERIALIZER_PACKAGE_NAME, + TypeSpec.classBuilder(className) + .addSuperinterface(Serializer.class) + .addModifiers(Modifier.PUBLIC) + .addAnnotation(AnnotationSpec.builder(Generated.class).addMember("value", getClass().getCanonicalName()).build()) + .addField(SchemaDescriptor.class, "schema", Modifier.PRIVATE, Modifier.FINAL) + .addField(ObjectFactory.class, "keyFactory", Modifier.PRIVATE, Modifier.FINAL) + .addField(ObjectFactory.class, "valFactory", Modifier.PRIVATE, Modifier.FINAL) + .addField(ArrayTypeName.of(VarHandle.class), "fieldAccessors", Modifier.PRIVATE, Modifier.FINAL) + .addMethod( + MethodSpec.constructorBuilder() + .addModifiers(Modifier.PUBLIC) + .addParameter(SchemaDescriptor.class, "schema") + .addParameter(Class.class, "keyClass") + .addParameter(Class.class, "valClass") + .addStatement("this.schema = schema") + .addStatement("this.keyFactory = $T.factoryForClass(keyClass)", MarshallerUtil.class) + .addStatement("this.valFactory = $T.factoryForClass(keyClass)", MarshallerUtil.class) + .addStatement("this.fieldAccessors = null") + .build() + ) + .addMethod(generateHelpersMetod(schema)) + .addMethod(generateSerializeMethod(keyMarsh, valMarsh)) + .addMethod(generateDeserializeKeyMethod(keyMarsh)) + .addMethod(generateDeserializeValueMethod()) + .build() + ) + .skipJavaLangImports(true) + .indent(TAB) + .build() + .writeTo(sb); + + return sb.toString(); } catch (Exception ex) { //TODO: fallback to java serializer? @@ -91,6 +189,128 @@ public class JaninoSerializerGenerator implements SerializerFactory { } } + private MethodSpec generateHelpersMetod(SchemaDescriptor schema) { + final MethodSpec.Builder builder = MethodSpec + .methodBuilder("createAssembler") + .addModifiers(Modifier.PRIVATE) + .addParameter(Object.class, "key") + .addParameter(Object.class, "val") + .returns(TupleAssembler.class) + + .addStatement("int nonNullVarlenKeys = 0; int nonNullVarlenValues = 0") + .addStatement("int nonNullVarlenKeysSize = 0; int nonNullVarlenValuesSize = 0") + .addStatement("$T keyCols = schema.keyColumns()", Columns.class) + .addStatement("$T valCols = schema.valueColumns()", Columns.class); + + Columns keyCols = schema.keyColumns(); + if (keyCols.firstVarlengthColumn() >= 0) { + final CodeBlock.Builder block = CodeBlock.builder().indent() + .addStatement("$T fVal", Object.class);// Temporary vars. + + for (int i = keyCols.firstVarlengthColumn(); i < keyCols.length(); i++) { + assert !keyCols.column(i).type().spec().fixedLength(); + + block.addStatement("assert !keyCols.column($L).type().spec().fixedLength()", i) + .addStatement("fVal = fieldAccessors[$L].get(key)", i) + .beginControlFlow("if (fVal != null)") + .addStatement("nonNullVarlenKeysSize += $T.getValueSize(fVal, keyCols.column($L).type())", MarshallerUtil.class, i) + .addStatement("nonNullVarlenKeys++") + .endControlFlow(); + } + block.unindent(); + + builder + .addCode("{\n") + .addCode(block.build()) + .addCode("}\n"); + } + + Columns valCols = schema.keyColumns(); + if (valCols.firstVarlengthColumn() >= 0) { + final CodeBlock.Builder block = CodeBlock.builder().indent() + .addStatement("$T fVal", Object.class);// Temporary vars. + + for (int i = valCols.firstVarlengthColumn(); i < valCols.length(); i++) { + assert !valCols.column(i).type().spec().fixedLength(); + + block.addStatement("assert !valCols.column($L).type().spec().fixedLength()", i) + .addStatement("fVal = fieldAccessors[$L].get(val)", i + schema.keyColumns().length()) + .beginControlFlow("if (fVal != null)") + .addStatement("nonNullVarlenValuesSize += $T.getValueSize(fVal, valCols.column($L).type())", MarshallerUtil.class, i) + .addStatement("nonNullVarlenValues++") + .endControlFlow(); + } + block.unindent(); + + builder + .addCode("{\n") + .addCode(block.build()) + .addCode("}\n"); + } + + builder.addStatement("int size = $T.tupleSize(keyCols, nonNullVarlenKeys, nonNullVarlenKeysSize," + + "valCols, nonNullVarlenValues, nonNullVarlenValuesSize)", TupleAssembler.class); + + builder.addStatement("return new $T(schema, size, nonNullVarlenKeys, nonNullVarlenValues)", TupleAssembler.class); + + return builder.build(); + } + + @NotNull private MethodSpec generateDeserializeValueMethod() { + return MethodSpec + .methodBuilder("deserializeValue") + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .addParameter(ArrayTypeName.of(TypeName.BYTE), "data") + .addException(SerializationException.class) + .returns(TypeName.OBJECT) + .addStatement("return null") + .build(); + } + + @NotNull private MethodSpec generateDeserializeKeyMethod(MarshallerExprGenerator keyMarsh) { + final MethodSpec.Builder builder = MethodSpec + .methodBuilder("deserializeKey") + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .addParameter(ArrayTypeName.of(TypeName.BYTE), "data") + .addException(SerializationException.class) + .returns(TypeName.OBJECT) + + .beginControlFlow("try") + .addStatement("$T tuple = new $T(schema, data)", Tuple.class, ByteBufferTuple.class) + .addCode(keyMarsh.unmarshallObjectCode("tuple")) + + .nextControlFlow("catch($T th)", Throwable.class) + .addStatement("throw new $T(th)", SerializationException.class) + .endControlFlow(); + + return builder.build(); + } + + @NotNull + private MethodSpec generateSerializeMethod(MarshallerExprGenerator keyMarsh, MarshallerExprGenerator valMarsh) { + return MethodSpec. + methodBuilder("serialize") + .addAnnotation(Override.class) + .addModifiers(Modifier.PUBLIC) + .addParameter(TypeName.OBJECT, "key") + .addParameter(TypeName.OBJECT, "val") + .addException(SerializationException.class) + .returns(ArrayTypeName.of(TypeName.BYTE.unbox())) + + .beginControlFlow("try") + .addStatement("$T asm = createAssembler(key, val)", TupleAssembler.class) + .addCode(keyMarsh.marshallObjectCode("asm", "key")) + .addCode(valMarsh.marshallObjectCode("asm", "val")) + .addStatement("return asm.build()") + + .nextControlFlow("catch($T th)", Throwable.class) + .addStatement("throw new $T(th)", SerializationException.class) + .endControlFlow() + .build(); + } + /** * Generates serializer code. * @@ -106,11 +326,10 @@ public class JaninoSerializerGenerator implements SerializerFactory { Class<?> keyClass, Class<?> valClass ) { - final String packageName = "org.apache.ignite.internal.schema.marshaller."; - final String className = "JaninoSerializerForSchema_" + schema.version(); + final String className = SERIALIZER_CLASS_NAME_PREFIX + schema.version(); // Prerequisites. - ce.setClassName(packageName + className); + ce.setClassName(SERIALIZER_PACKAGE_NAME + className); ce.setImplementedInterfaces(new Class[] {Serializer.class}); ce.setDefaultImports( "java.util.UUID", @@ -178,9 +397,13 @@ public class JaninoSerializerGenerator implements SerializerFactory { BinaryMode mode = MarshallerUtil.mode(aClass); if (mode != null) - return new IdentityObjectMarshallerExprGenerator(FieldAccessExprGenerator.createIdentityAccessor(mode, firstColIdx)); + return new IdentityObjectMarshallerExprGenerator( + FieldAccessExprGenerator.createIdentityAccessor(mode, firstColIdx), + TupleAccessorExpr.createAccessor(mode, firstColIdx) + ); FieldAccessExprGenerator[] accessors = new FieldAccessExprGenerator[columns.length()]; + TupleAccessorExpr[] tupleAccessorExprs = new TupleAccessorExpr[] {}; try { for (int i = 0; i < columns.length(); i++) { final Field field = aClass.getDeclaredField(columns.column(i).name()); @@ -188,14 +411,14 @@ public class JaninoSerializerGenerator implements SerializerFactory { accessors[i] = FieldAccessExprGenerator.createAccessor( MarshallerUtil.mode(field.getType()), firstColIdx + i /* schma absolute index. */, - IgniteUnsafeUtils.objectFieldOffset(field)); + 0L);// IgniteUnsafeUtils.objectFieldOffset(field)); } } catch (NoSuchFieldException ex) { throw new IllegalStateException(ex); } - return new MarshallerExprGenerator(factoryRefExpr, accessors); + return new MarshallerExprGenerator(factoryRefExpr, accessors, tupleAccessorExprs); } /** diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java index 433b567..8087e2c 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java @@ -17,6 +17,8 @@ package org.apache.ignite.internal.schema.marshaller.generator; +import com.squareup.javapoet.CodeBlock; +import java.lang.invoke.VarHandle; import org.apache.ignite.internal.schema.marshaller.Serializer; /** @@ -28,6 +30,7 @@ class MarshallerExprGenerator { /** Object field access expression generators. */ protected FieldAccessExprGenerator[] accessors; + protected TupleAccessorExpr[] tupleAccessors; /** * Constructor. @@ -35,9 +38,11 @@ class MarshallerExprGenerator { * @param factoryRefExpr Object factory regerence expression. * @param accessors Object field access expression generators. */ - public MarshallerExprGenerator(String factoryRefExpr, FieldAccessExprGenerator[] accessors) { + public MarshallerExprGenerator(String factoryRefExpr, FieldAccessExprGenerator[] accessors, + TupleAccessorExpr[] tupleAccessors) { this.accessors = accessors; this.factoryRefExpr = factoryRefExpr; + this.tupleAccessors = tupleAccessors; } /** @@ -91,4 +96,25 @@ class MarshallerExprGenerator { sb.append(indent).append(JaninoSerializerGenerator.TAB + "throw new SerializationException(ex);").append(JaninoSerializerGenerator.LF); sb.append(indent).append("}" + JaninoSerializerGenerator.LF); } + + public CodeBlock unmarshallObjectCode(String tupleExpr) { + final CodeBlock.Builder builder = CodeBlock.builder() + .add("Object obj = ").add(factoryRefExpr).addStatement(".create()"); + + for (int i = 0; i < tupleAccessors.length; i++) { + builder.addStatement("fieldAccessor[$L].set(obj, $L)", i, tupleAccessors[i].read(tupleExpr).toString()); + } + + builder.addStatement("return obj"); + return builder.build(); + } + + public CodeBlock marshallObjectCode(String asm, String objVar) { + final CodeBlock.Builder builder = CodeBlock.builder(); + + for (int i = 0; i < tupleAccessors.length; i++) + builder.addStatement(tupleAccessors[i].write(asm, CodeBlock.of("fieldAccessor[$L].get($L)", i, objVar).toString())); + + return builder.build(); + } } diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java new file mode 100644 index 0000000..e1b782d --- /dev/null +++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.ignite.internal.schema.marshaller.generator; + +import com.squareup.javapoet.CodeBlock; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import org.apache.ignite.internal.schema.Tuple; +import org.apache.ignite.internal.schema.TupleAssembler; +import org.apache.ignite.internal.schema.marshaller.BinaryMode; + +/** + * Object field access expression generators. + */ +public class TupleAccessorExpr { + public static final MethodHandle BYTE_READ; + public static final MethodHandle SHORT_READ; + public static final MethodHandle INT_READ; + public static final MethodHandle LONG_READ; + public static final MethodHandle FLOAT_READ; + public static final MethodHandle DOUBLE_READ; + public static final MethodHandle BYTE_BOXED_READ; + public static final MethodHandle SHORT_BOXED_READ; + public static final MethodHandle INT_BOXED_READ; + public static final MethodHandle LONG_BOXED_READ; + public static final MethodHandle FLOAT_BOXED_READ; + public static final MethodHandle DOUBLE_BOXED_READ; + + public static final MethodHandle BYTE_WRITE; + public static final MethodHandle SHORT_WRITE; + public static final MethodHandle INT_WRITE; + public static final MethodHandle LONG_WRITE; + public static final MethodHandle FLOAT_WRITE; + public static final MethodHandle DOUBLE_WRITE; + public static final MethodHandle NULL_WRITE; + + static { + try { + MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Tuple.class,MethodHandles.lookup()); + + BYTE_READ = lookup.findVirtual(Tuple.class, "byteValue", MethodType.methodType(byte.class, int.class)); + SHORT_READ = lookup.findVirtual(Tuple.class, "shortValue", MethodType.methodType(short.class, int.class)); + INT_READ = lookup.findVirtual(Tuple.class, "intValue", MethodType.methodType(int.class, int.class)); + LONG_READ = lookup.findVirtual(Tuple.class, "longValue", MethodType.methodType(long.class, int.class)); + FLOAT_READ = lookup.findVirtual(Tuple.class, "floatValue", MethodType.methodType(float.class, int.class)); + DOUBLE_READ = lookup.findVirtual(Tuple.class, "doubleValue", MethodType.methodType(double.class, int.class)); + BYTE_BOXED_READ = lookup.findVirtual(Tuple.class, "byteValueBoxed", MethodType.methodType(Byte.class, int.class)); + SHORT_BOXED_READ = lookup.findVirtual(Tuple.class, "shortValueBoxed", MethodType.methodType(Short.class, int.class)); + INT_BOXED_READ = lookup.findVirtual(Tuple.class, "intValueBoxed", MethodType.methodType(Integer.class, int.class)); + LONG_BOXED_READ = lookup.findVirtual(Tuple.class, "longValueBoxed", MethodType.methodType(Long.class, int.class)); + FLOAT_BOXED_READ = lookup.findVirtual(Tuple.class, "floatValueBoxed", MethodType.methodType(Float.class, int.class)); + DOUBLE_BOXED_READ = lookup.findVirtual(Tuple.class, "doubleValueBoxed", MethodType.methodType(Double.class, int.class)); + + lookup = MethodHandles.privateLookupIn(TupleAssembler.class,MethodHandles.lookup()); + NULL_WRITE = lookup.findVirtual(TupleAssembler.class, "appendNull", MethodType.methodType(void.class)); + BYTE_WRITE = lookup.findVirtual(TupleAssembler.class, "appendByte", MethodType.methodType(void.class, byte.class)); + SHORT_WRITE = lookup.findVirtual(TupleAssembler.class, "appendShort", MethodType.methodType(void.class, short.class)); + INT_WRITE = lookup.findVirtual(TupleAssembler.class, "appendInt", MethodType.methodType(void.class, int.class)); + LONG_WRITE = lookup.findVirtual(TupleAssembler.class, "appendLong", MethodType.methodType(void.class, long.class)); + FLOAT_WRITE = lookup.findVirtual(TupleAssembler.class, "appendFloat", MethodType.methodType(void.class, float.class)); + DOUBLE_WRITE = lookup.findVirtual(TupleAssembler.class, "appendDouble", MethodType.methodType(void.class, double.class)); + } + catch (NoSuchMethodException | IllegalAccessException e) { + throw new IllegalStateException(e); + } + + } + + private final Class<?> rType; + + static TupleAccessorExpr createAccessor(BinaryMode mode, int colIdx) { + switch (mode) { + case P_BYTE: + return new TupleAccessorExpr("BYTE_READ", "BYTE_WRITE", byte.class, colIdx); + case P_SHORT: + break; + case P_INT: + break; + case P_LONG: + break; + case P_FLOAT: + break; + case P_DOUBLE: + break; + case BYTE: + return new TupleAccessorExpr("BYTE_BOXED_READ", "BYTE_WRITE", Byte.class, colIdx); + case SHORT: + break; + case INT: + break; + case LONG: + break; + case FLOAT: + break; + case DOUBLE: + break; + case STRING: + break; + case UUID: + break; + case BYTE_ARR: + break; + case BITSET: + break; + } + + throw new IllegalStateException("Unsupported binary mode: " + mode); + } + + private final String readExpr; + private final String writeExpr; + private final int colIdx; + + private TupleAccessorExpr(String readExpr, String writeExpr, Class<?> rType, int colIdx) { + this.readExpr = readExpr; + this.writeExpr = writeExpr; + this.colIdx = colIdx; + this.rType = rType; + } + + public CodeBlock read(String tuple) { + return CodeBlock.of("($T)$T.$L.invoke($L, $L)", rType, TupleAccessorExpr.class, readExpr, tuple, colIdx); + } + + public CodeBlock write(String asmVar, String valExpr) { + if (rType.isPrimitive()) + return CodeBlock.of("$T.$L.invoke($L, $L)", TupleAccessorExpr.class, writeExpr, asmVar, valExpr); + else { + return CodeBlock.builder() + .add("{\n").indent() + .addStatement("$T fVal", rType) + .beginControlFlow("if((fVal = ($T)$L) == null)", rType, valExpr) + .addStatement("$T.NULL_WRITE.invokeExact($L)", TupleAccessorExpr.class, asmVar) + .nextControlFlow("else") + .addStatement("$T.$L.invoke($L, fVal)", TupleAccessorExpr.class, writeExpr, asmVar) + .endControlFlow() + .unindent() + .add("}\n") + .build(); + } + } +} diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/FieldAccessor.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/FieldAccessor.java index 97ea038..812b02e 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/FieldAccessor.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/FieldAccessor.java @@ -478,9 +478,7 @@ public abstract class FieldAccessor { assert obj != null; assert writer != null; - Object val; - - val = varHandle.get(obj); + Object val = varHandle.get(obj); if (val == null) { writer.appendNull(); diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/util/ObjectFactory.java b/modules/commons/src/main/java/org/apache/ignite/internal/util/ObjectFactory.java index f31965f..b888955 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/util/ObjectFactory.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/util/ObjectFactory.java @@ -17,15 +17,16 @@ package org.apache.ignite.internal.util; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; /** * Object factory. */ public class ObjectFactory<T> implements Factory<T> { /** Class default constructor. */ - private final Constructor<T> cnstr; + private final MethodHandle constr; /** * Constructor. @@ -34,11 +35,9 @@ public class ObjectFactory<T> implements Factory<T> { */ public ObjectFactory(Class<T> tClass) { try { - cnstr = tClass.getDeclaredConstructor(); - - cnstr.setAccessible(true); + constr = MethodHandles.privateLookupIn(tClass, MethodHandles.lookup()).findConstructor(tClass, MethodType.methodType(void.class)); } - catch (NoSuchMethodException e) { + catch (NoSuchMethodException | IllegalAccessException e) { throw new IllegalStateException("Class has no default constructor: class=" + tClass.getName(), e); } } @@ -46,17 +45,10 @@ public class ObjectFactory<T> implements Factory<T> { /** {@inheritDoc} */ @Override public T create() throws IllegalStateException { try { - return cnstr.newInstance(); + return (T)constr.invoke(); } - catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { - throw new IllegalStateException("Failed to instantiate class: " + cnstr.getDeclaringClass().getName(), e); + catch (Throwable e) { + throw new IllegalStateException("Failed to instantiate class: " + constr.type().returnType(), e); } } - - /** - * @return Class of object created by the factory. - */ - public Class<T> getClazz() { - return cnstr.getDeclaringClass(); - } } diff --git a/pom.xml b/pom.xml index 7d1a734..0ad6c7c 100644 --- a/pom.xml +++ b/pom.xml @@ -50,6 +50,7 @@ <!-- Dependencies versions. --> <janino.version>3.0.11</janino.version> + <javapoet.version>1.13.0</javapoet.version> <javax.annotation.api.version>1.3.2</javax.annotation.api.version> <jetbrains.annotations.version>20.1.0</jetbrains.annotations.version> <jmh.framework.verion>1.9.3</jmh.framework.verion>