Skip to content

Commit

Permalink
DynamicCodec tweaks to make it into a super fast String serializer.
Browse files Browse the repository at this point in the history
(3-8x faster than StringCodec).

PiperOrigin-RevId: 196615858
  • Loading branch information
aoeui authored and Copybara-Service committed May 15, 2018
1 parent eb5a80c commit 150a906
Showing 1 changed file with 41 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

package com.google.devtools.build.lib.skyframe.serialization;

import com.google.common.collect.ImmutableSortedMap;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.UnsafeProvider;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.CodedOutputStream;
Expand All @@ -26,6 +25,7 @@
import java.nio.ByteBuffer;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
import sun.reflect.ReflectionFactory;

/**
Expand All @@ -37,7 +37,7 @@ public class DynamicCodec implements ObjectCodec<Object> {

private final Class<?> type;
private final Constructor<?> constructor;
private final ImmutableSortedMap<Field, Long> offsets;
private final TypeAndOffset[] offsets;

public DynamicCodec(Class<?> type) throws ReflectiveOperationException {
this.type = type;
Expand All @@ -58,8 +58,8 @@ public MemoizationStrategy getStrategy() {
@Override
public void serialize(SerializationContext context, Object obj, CodedOutputStream codedOut)
throws SerializationException, IOException {
for (Map.Entry<Field, Long> entry : offsets.entrySet()) {
serializeField(context, codedOut, obj, entry.getKey().getType(), entry.getValue());
for (int i = 0; i < offsets.length; ++i) {
serializeField(context, codedOut, obj, offsets[i].type, offsets[i].offset);
}
}

Expand Down Expand Up @@ -105,6 +105,15 @@ private void serializeField(
}
} else if (type.isArray()) {
Object arr = UnsafeProvider.getInstance().getObject(obj, offset);
if (type.getComponentType().equals(byte.class)) {
if (arr == null) {
codedOut.writeBoolNoTag(false);
} else {
codedOut.writeBoolNoTag(true);
codedOut.writeByteArrayNoTag((byte[]) arr);
}
return;
}
if (arr == null) {
codedOut.writeInt32NoTag(-1);
return;
Expand Down Expand Up @@ -140,8 +149,8 @@ public Object deserialize(DeserializationContext context, CodedInputStream coded
throw new SerializationException("Could not instantiate object of type: " + type, e);
}
context.registerInitialValue(instance);
for (Map.Entry<Field, Long> entry : offsets.entrySet()) {
deserializeField(context, codedIn, instance, entry.getKey().getType(), entry.getValue());
for (int i = 0; i < offsets.length; ++i) {
deserializeField(context, codedIn, instance, offsets[i].type, offsets[i].offset);
}
return instance;
}
Expand Down Expand Up @@ -185,6 +194,12 @@ private void deserializeField(
throw new UnsupportedOperationException("Unknown primitive type: " + type);
}
} else if (type.isArray()) {
if (type.getComponentType().equals(byte.class)) {
boolean isNonNull = codedIn.readBool();
UnsafeProvider.getInstance()
.putObject(obj, offset, isNonNull ? codedIn.readByteArray() : null);
return;
}
int length = codedIn.readInt32();
if (length < 0) {
UnsafeProvider.getInstance().putObject(obj, offset, null);
Expand All @@ -206,9 +221,8 @@ private void deserializeField(
}
}

private static <T> ImmutableSortedMap<Field, Long> getOffsets(Class<T> type) {
ImmutableSortedMap.Builder<Field, Long> offsets =
new ImmutableSortedMap.Builder<>(new FieldComparator());
private static <T> TypeAndOffset[] getOffsets(Class<T> type) {
TreeMap<Field, Long> offsets = new TreeMap<>(new FieldComparator());
for (Class<? super T> next = type; next != null; next = next.getSuperclass()) {
for (Field field : next.getDeclaredFields()) {
if ((field.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) != 0) {
Expand All @@ -218,7 +232,24 @@ private static <T> ImmutableSortedMap<Field, Long> getOffsets(Class<T> type) {
offsets.put(field, UnsafeProvider.getInstance().objectFieldOffset(field));
}
}
return offsets.build();
// Converts to an array to make it easy to avoid the use of iterators.
TypeAndOffset[] offsetsArr = new TypeAndOffset[offsets.size()];
int i = 0;
for (Map.Entry<Field, Long> entry : offsets.entrySet()) {
offsetsArr[i] = new TypeAndOffset(entry.getKey().getType(), entry.getValue());
++i;
}
return offsetsArr;
}

private static class TypeAndOffset {
public final Class<?> type;
public final long offset;

public TypeAndOffset(Class<?> type, long offset) {
this.type = type;
this.offset = offset;
}
}

private static Constructor<?> getConstructor(Class<?> type) throws ReflectiveOperationException {
Expand Down

0 comments on commit 150a906

Please sign in to comment.