Skip to content

Commit

Permalink
refactor(java): Streamline ClassResolver responsibilities
Browse files Browse the repository at this point in the history
To reduce the complexity of the `ClassResolver` class, we
mainly do the following two things:

1. Move ClassId related responsibilities into ClassIdAllocator class.

2. Move `registeredId2ClassInfo` into `ExtRegistry` static inner
class since they are content related.

Signed-off-by: LiangliangSui <[email protected]>
  • Loading branch information
LiangliangSui committed Mar 21, 2024
1 parent c294885 commit f0e34b4
Show file tree
Hide file tree
Showing 15 changed files with 419 additions and 264 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ on:
push:
branches:
- main
- sll3
- 'releases/**'
- 'deploy/**'
- 'test*'
Expand Down
37 changes: 19 additions & 18 deletions java/fury-core/src/main/java/org/apache/fury/Fury.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.apache.fury.config.LongEncoding;
import org.apache.fury.memory.MemoryBuffer;
import org.apache.fury.memory.MemoryUtils;
import org.apache.fury.resolver.ClassIdAllocator.BuiltinClassId;
import org.apache.fury.resolver.ClassInfo;
import org.apache.fury.resolver.ClassInfoHolder;
import org.apache.fury.resolver.ClassResolver;
Expand Down Expand Up @@ -514,35 +515,35 @@ public <T> void xwriteNonRef(MemoryBuffer buffer, T obj, Serializer<T> serialize
/** Write not null data to buffer. */
private void writeData(MemoryBuffer buffer, ClassInfo classInfo, Object obj) {
switch (classInfo.getClassId()) {
case ClassResolver.BOOLEAN_CLASS_ID:
case BuiltinClassId.BOOLEAN_CLASS_ID:
buffer.writeBoolean((Boolean) obj);
break;
case ClassResolver.BYTE_CLASS_ID:
case BuiltinClassId.BYTE_CLASS_ID:
buffer.writeByte((Byte) obj);
break;
case ClassResolver.CHAR_CLASS_ID:
case BuiltinClassId.CHAR_CLASS_ID:
buffer.writeChar((Character) obj);
break;
case ClassResolver.SHORT_CLASS_ID:
case BuiltinClassId.SHORT_CLASS_ID:
buffer.writeShort((Short) obj);
break;
case ClassResolver.INTEGER_CLASS_ID:
case BuiltinClassId.INTEGER_CLASS_ID:
if (compressInt) {
buffer.writeVarInt((Integer) obj);
} else {
buffer.writeInt((Integer) obj);
}
break;
case ClassResolver.FLOAT_CLASS_ID:
case BuiltinClassId.FLOAT_CLASS_ID:
buffer.writeFloat((Float) obj);
break;
case ClassResolver.LONG_CLASS_ID:
case BuiltinClassId.LONG_CLASS_ID:
LongSerializer.writeLong(buffer, (Long) obj, longEncoding);
break;
case ClassResolver.DOUBLE_CLASS_ID:
case BuiltinClassId.DOUBLE_CLASS_ID:
buffer.writeDouble((Double) obj);
break;
case ClassResolver.STRING_CLASS_ID:
case BuiltinClassId.STRING_CLASS_ID:
stringSerializer.writeJavaString(buffer, (String) obj);
break;
// TODO(add fastpath for other types)
Expand Down Expand Up @@ -870,27 +871,27 @@ public Object readData(MemoryBuffer buffer, ClassInfo classInfo) {

private Object readDataInternal(MemoryBuffer buffer, ClassInfo classInfo) {
switch (classInfo.getClassId()) {
case ClassResolver.BOOLEAN_CLASS_ID:
case BuiltinClassId.BOOLEAN_CLASS_ID:
return buffer.readBoolean();
case ClassResolver.BYTE_CLASS_ID:
case BuiltinClassId.BYTE_CLASS_ID:
return buffer.readByte();
case ClassResolver.CHAR_CLASS_ID:
case BuiltinClassId.CHAR_CLASS_ID:
return buffer.readChar();
case ClassResolver.SHORT_CLASS_ID:
case BuiltinClassId.SHORT_CLASS_ID:
return buffer.readShort();
case ClassResolver.INTEGER_CLASS_ID:
case BuiltinClassId.INTEGER_CLASS_ID:
if (compressInt) {
return buffer.readVarInt();
} else {
return buffer.readInt();
}
case ClassResolver.FLOAT_CLASS_ID:
case BuiltinClassId.FLOAT_CLASS_ID:
return buffer.readFloat();
case ClassResolver.LONG_CLASS_ID:
case BuiltinClassId.LONG_CLASS_ID:
return LongSerializer.readLong(buffer, longEncoding);
case ClassResolver.DOUBLE_CLASS_ID:
case BuiltinClassId.DOUBLE_CLASS_ID:
return buffer.readDouble();
case ClassResolver.STRING_CLASS_ID:
case BuiltinClassId.STRING_CLASS_ID:
return stringSerializer.readJavaString(buffer);
// TODO(add fastpath for other types)
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@
import org.apache.fury.codegen.ExpressionOptimizer;
import org.apache.fury.codegen.ExpressionUtils;
import org.apache.fury.collection.Tuple2;
import org.apache.fury.resolver.ClassIdAllocator.BuiltinClassId;
import org.apache.fury.resolver.ClassInfo;
import org.apache.fury.resolver.ClassResolver;
import org.apache.fury.resolver.FieldResolver;
import org.apache.fury.resolver.FieldResolver.CollectionFieldInfo;
import org.apache.fury.resolver.FieldResolver.FieldInfo;
Expand Down Expand Up @@ -879,7 +879,7 @@ protected Expression getFinalClassInfo(Class<?> cls) {
protected Expression writeFinalClassInfo(Expression buffer, Class<?> cls) {
Preconditions.checkArgument(ReflectionUtils.isMonomorphic(cls));
ClassInfo classInfo = visitFury(f -> f.getClassResolver().getClassInfo(cls, false));
if (classInfo != null && classInfo.getClassId() != ClassResolver.NO_CLASS_ID) {
if (classInfo != null && classInfo.getClassId() != BuiltinClassId.NO_CLASS_ID) {
return fury.getClassResolver().writeClassExpr(buffer, classInfo.getClassId());
}
Expression classInfoExpr = getFinalClassInfo(cls);
Expand All @@ -889,7 +889,7 @@ protected Expression writeFinalClassInfo(Expression buffer, Class<?> cls) {
protected Expression skipFinalClassInfo(Class<?> cls, Expression buffer) {
Preconditions.checkArgument(ReflectionUtils.isMonomorphic(cls));
ClassInfo classInfo = visitFury(f -> f.getClassResolver().getClassInfo(cls, false));
if (classInfo != null && classInfo.getClassId() != ClassResolver.NO_CLASS_ID) {
if (classInfo != null && classInfo.getClassId() != BuiltinClassId.NO_CLASS_ID) {
return fury.getClassResolver().skipRegisteredClassExpr(buffer);
}
// read `ClassInfo` is not used, set `inlineReadClassInfo` false,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* 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.fury.resolver;

import java.util.function.Function;
import org.apache.fury.util.Preconditions;

/** Responsible for allocating ClassId and maintaining built-in ClassId. */
public class ClassIdAllocator {
public static class BuiltinClassId {
// preserve 0 as flag for class id not set in ClassInfo`
public static final short NO_CLASS_ID = (short) 0;
public static final short LAMBDA_STUB_ID = 1;
public static final short JDK_PROXY_STUB_ID = 2;
public static final short REPLACE_STUB_ID = 3;
// Note: following pre-defined class id should be continuous, since they may be used based
// range.
public static final short PRIMITIVE_VOID_CLASS_ID = (short) (REPLACE_STUB_ID + 1);
public static final short PRIMITIVE_BOOLEAN_CLASS_ID = (short) (PRIMITIVE_VOID_CLASS_ID + 1);
public static final short PRIMITIVE_BYTE_CLASS_ID = (short) (PRIMITIVE_VOID_CLASS_ID + 2);
public static final short PRIMITIVE_CHAR_CLASS_ID = (short) (PRIMITIVE_VOID_CLASS_ID + 3);
public static final short PRIMITIVE_SHORT_CLASS_ID = (short) (PRIMITIVE_VOID_CLASS_ID + 4);
public static final short PRIMITIVE_INT_CLASS_ID = (short) (PRIMITIVE_VOID_CLASS_ID + 5);
public static final short PRIMITIVE_FLOAT_CLASS_ID = (short) (PRIMITIVE_VOID_CLASS_ID + 6);
public static final short PRIMITIVE_LONG_CLASS_ID = (short) (PRIMITIVE_VOID_CLASS_ID + 7);
public static final short PRIMITIVE_DOUBLE_CLASS_ID = (short) (PRIMITIVE_VOID_CLASS_ID + 8);
public static final short VOID_CLASS_ID = (short) (PRIMITIVE_DOUBLE_CLASS_ID + 1);
public static final short BOOLEAN_CLASS_ID = (short) (VOID_CLASS_ID + 1);
public static final short BYTE_CLASS_ID = (short) (VOID_CLASS_ID + 2);
public static final short CHAR_CLASS_ID = (short) (VOID_CLASS_ID + 3);
public static final short SHORT_CLASS_ID = (short) (VOID_CLASS_ID + 4);
public static final short INTEGER_CLASS_ID = (short) (VOID_CLASS_ID + 5);
public static final short FLOAT_CLASS_ID = (short) (VOID_CLASS_ID + 6);
public static final short LONG_CLASS_ID = (short) (VOID_CLASS_ID + 7);
public static final short DOUBLE_CLASS_ID = (short) (VOID_CLASS_ID + 8);
public static final short STRING_CLASS_ID = (short) (VOID_CLASS_ID + 9);
public static final short PRIMITIVE_BOOLEAN_ARRAY_CLASS_ID = (short) (STRING_CLASS_ID + 1);
public static final short PRIMITIVE_BYTE_ARRAY_CLASS_ID = (short) (STRING_CLASS_ID + 2);
public static final short PRIMITIVE_CHAR_ARRAY_CLASS_ID = (short) (STRING_CLASS_ID + 3);
public static final short PRIMITIVE_SHORT_ARRAY_CLASS_ID = (short) (STRING_CLASS_ID + 4);
public static final short PRIMITIVE_INT_ARRAY_CLASS_ID = (short) (STRING_CLASS_ID + 5);
public static final short PRIMITIVE_FLOAT_ARRAY_CLASS_ID = (short) (STRING_CLASS_ID + 6);
public static final short PRIMITIVE_LONG_ARRAY_CLASS_ID = (short) (STRING_CLASS_ID + 7);
public static final short PRIMITIVE_DOUBLE_ARRAY_CLASS_ID = (short) (STRING_CLASS_ID + 8);
public static final short STRING_ARRAY_CLASS_ID = (short) (PRIMITIVE_DOUBLE_ARRAY_CLASS_ID + 1);
public static final short OBJECT_ARRAY_CLASS_ID = (short) (PRIMITIVE_DOUBLE_ARRAY_CLASS_ID + 2);
public static final short ARRAYLIST_CLASS_ID = (short) (PRIMITIVE_DOUBLE_ARRAY_CLASS_ID + 3);
public static final short HASHMAP_CLASS_ID = (short) (PRIMITIVE_DOUBLE_ARRAY_CLASS_ID + 4);
public static final short HASHSET_CLASS_ID = (short) (PRIMITIVE_DOUBLE_ARRAY_CLASS_ID + 5);
public static final short CLASS_CLASS_ID = (short) (PRIMITIVE_DOUBLE_ARRAY_CLASS_ID + 6);
public static final short EMPTY_OBJECT_ID = (short) (PRIMITIVE_DOUBLE_ARRAY_CLASS_ID + 7);
}

// class id of last default registered class.
private short innerEndClassId;
// Here we set it to 1 because `NO_CLASS_ID` is 0 to avoid calculating it again in
// `register(Class<?> cls)`.
private short classIdGenerator = 1;

private final Function<Class<?>, Boolean> classRegisteredFactory;

private final Function<Short, Boolean> classIdRegisteredFactory;

public ClassIdAllocator(
Function<Class<?>, Boolean> classRegisteredFactory,
Function<Short, Boolean> classIdRegisteredFactory) {
Preconditions.checkNotNull(classRegisteredFactory);
Preconditions.checkNotNull(classIdRegisteredFactory);
this.classRegisteredFactory = classRegisteredFactory;
this.classIdRegisteredFactory = classIdRegisteredFactory;
}

public short allocateClassId(Class<?> cls) {
if (!classRegisteredFactory.apply(cls)) {
while (classIdRegisteredFactory.apply(classIdGenerator)) {
classIdGenerator++;
}
}
return classIdGenerator;
}

public void notifyRegistrationEnd() {
classIdGenerator++;
}

public void markInternalRegistrationEnd() {
innerEndClassId = classIdGenerator;
}

public boolean isInnerClass(Short classId) {
return classId != null && classId != BuiltinClassId.NO_CLASS_ID && classId < innerEndClassId;
}

public boolean isPrimitive(short classId) {
return classId >= BuiltinClassId.PRIMITIVE_VOID_CLASS_ID
&& classId <= BuiltinClassId.PRIMITIVE_DOUBLE_CLASS_ID;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public class ClassInfo {
this.typeTagBytes = typeTagBytes;
this.serializer = serializer;
this.classId = classId;
if (cls != null && classId == ClassResolver.NO_CLASS_ID) {
if (cls != null && classId == ClassIdAllocator.BuiltinClassId.NO_CLASS_ID) {
Preconditions.checkArgument(classNameBytes != null);
}
}
Expand All @@ -78,7 +78,8 @@ public class ClassInfo {
this.fullClassNameBytes = null;
}
if (cls != null
&& (classId == ClassResolver.NO_CLASS_ID || classId == ClassResolver.REPLACE_STUB_ID)) {
&& (classId == ClassIdAllocator.BuiltinClassId.NO_CLASS_ID
|| classId == ClassIdAllocator.BuiltinClassId.REPLACE_STUB_ID)) {
// REPLACE_STUB_ID for write replace class in `ClassSerializer`.
String packageName = ReflectionUtils.getPackage(cls);
this.packageNameBytes = enumStringResolver.getOrCreateEnumStringBytes(packageName);
Expand All @@ -100,10 +101,10 @@ public class ClassInfo {
boolean isProxy = ReflectionUtils.isJdkProxy(cls);
this.isDynamicGeneratedClass = isLambda || isProxy;
if (isLambda) {
this.classId = ClassResolver.LAMBDA_STUB_ID;
this.classId = ClassIdAllocator.BuiltinClassId.LAMBDA_STUB_ID;
}
if (isProxy) {
this.classId = ClassResolver.JDK_PROXY_STUB_ID;
this.classId = ClassIdAllocator.BuiltinClassId.JDK_PROXY_STUB_ID;
}
} else {
this.isDynamicGeneratedClass = false;
Expand Down
Loading

0 comments on commit f0e34b4

Please sign in to comment.