use of org.curioswitch.common.protobuf.json.bytebuddy.SetJumpTargetLabel in project curiostack by curioswitch.
the class DoParse method setRepeatedFieldValue.
/**
* Returns the {@link StackManipulation} for setting the value of a normal repeated field.
*
* <p>Roughly equivalent to:
*
* <pre>{@code
* ParseSupport.parseArrayStart(parser);
* while (!ParseSupport.checkArrayEnd(parser)) {
* builder.addFoo(readValue());
* }
* }</pre>
*/
private StackManipulation setRepeatedFieldValue(ProtoFieldInfo info, Label beforeReadField, LocalVariables<LocalVariable> locals, Map<String, FieldDescription> fieldsByName, StackManipulation setSingleValue) {
Label arrayStart = new Label();
StackManipulation.Compound beforeRead = new StackManipulation.Compound(locals.load(LocalVariable.parser), ParseSupport_parseArrayStart, new SetJumpTargetLabel(arrayStart), locals.load(LocalVariable.parser), ParseSupport_throwIfRepeatedNull, locals.load(LocalVariable.parser), ParseSupport_checkArrayEnd, new IfTrue(beforeReadField));
Label afterSet = new Label();
StackManipulation.Compound setValueAndPrepareForNext = new StackManipulation.Compound(setSingleValue, Removal.SINGLE, new SetJumpTargetLabel(afterSet), locals.load(LocalVariable.parser), Parser_nextValue, Removal.SINGLE, new Goto(arrayStart));
if (info.valueType() == Type.ENUM) {
// We special-case enum since we may need to skip unknown values.
return new StackManipulation.Compound(beforeRead, locals.load(LocalVariable.parser), readValue(info, fieldsByName, locals), locals.store(LocalVariable.intvalue), locals.load(LocalVariable.intvalue), IntegerConstant.forValue(-1), new IfEqual(int.class, afterSet), locals.load(LocalVariable.builder), locals.load(LocalVariable.intvalue), setValueAndPrepareForNext);
} else {
return new StackManipulation.Compound(beforeRead, locals.load(LocalVariable.builder), locals.load(LocalVariable.parser), readValue(info, fieldsByName, locals), setValueAndPrepareForNext);
}
}
use of org.curioswitch.common.protobuf.json.bytebuddy.SetJumpTargetLabel in project curiostack by curioswitch.
the class DoParse method apply.
@Override
public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
Map<String, FieldDescription> fieldsByName = CodeGenUtil.fieldsByName(implementationContext);
List<FieldDescriptor> sortedFields = CodeGenUtil.sorted(descriptor.getFields());
// Fields stored in order of number, so to get the highest number we take the last field.
FieldDescriptor lastField = !sortedFields.isEmpty() ? sortedFields.get(sortedFields.size() - 1) : null;
// Field numbers are 1 or greater so we will allocate the same size as the last field number
// and subtract 1 when keeping track.
int lastFieldNumber = lastField != null ? lastField.getNumber() : 0;
int numFieldPresenceWords = lastFieldNumber / Integer.SIZE;
if (lastFieldNumber % Integer.SIZE > 0) {
numFieldPresenceWords++;
}
LocalVariable[] fieldPresenceVars = new LocalVariable[numFieldPresenceWords];
for (int i = 0; i < numFieldPresenceWords; i++) {
fieldPresenceVars[i] = new LocalVariable("setFieldBits" + i);
}
LocalVariable[] handles = Arrays.copyOf(LocalVariable.values(), LocalVariable.values().length + fieldPresenceVars.length);
System.arraycopy(fieldPresenceVars, 0, handles, LocalVariable.values().length, fieldPresenceVars.length);
LocalVariables.Builder<LocalVariable> localsBuilder = LocalVariables.builderForMethod(instrumentedMethod, handles).add(builderClass, LocalVariable.builder).add(String.class, LocalVariable.fieldName).add(int.class, LocalVariable.intvalue).add(int.class, LocalVariable.intMapKey).add(long.class, LocalVariable.longMapKey).add(boolean.class, LocalVariable.boolMapKey).add(String.class, LocalVariable.stringMapKey);
for (LocalVariable fieldPresenceVar : fieldPresenceVars) {
localsBuilder.add(int.class, fieldPresenceVar);
}
LocalVariables<LocalVariable> locals = localsBuilder.build();
List<StackManipulation> stackManipulations = new ArrayList<>();
Label beforeReadField = new Label();
Label finished = new Label();
// Initialize local variables for this method, e.g.,
// void doMerge(JsonParser parser, int currentDepth, Message.Builder messageBuilder) {
// T builder = (T) messageBuilder;
// String fieldName = null;
// Object fieldNumberUnboxed = null;
// int fieldNumber = 0;
// int setFieldBits0 = 0;
// int setFieldBits1 = 0;
// ...
stackManipulations.addAll(Arrays.asList(locals.initialize(), locals.load(LocalVariable.messageBuilder), TypeCasting.to(new ForLoadedType(builderClass)), locals.store(LocalVariable.builder)));
// Begins the loop that reads fields from the JSON, reading the field name and computing its
// hash, e.g.,
// ...
// while (parser.nextValue() != ParseSupport.checkObjectEnd) {
// fieldName = parser.getCurrentName();
// fieldNumberUnboxed = FIELD_NUMBERS.get(fieldName):
// if (fieldNumberUnboxed == null) {
// ParseSupport.throwIfUnknownField(fieldName, descriptor.getFullName());
// return
// }
// fieldNumber = (int) fieldNumberUnboxed;
// ...
stackManipulations.addAll(Arrays.asList(new SetJumpTargetLabel(beforeReadField), locals.load(LocalVariable.parser), Parser_nextValue, ParseSupport_checkObjectEnd, new IfTrue(finished), locals.load(LocalVariable.parser), Parser_getCurrentName, locals.store(LocalVariable.fieldName)));
for (FieldDescriptor f : sortedFields) {
Label afterNameCheck = new Label();
Label afterField = new Label();
ProtoFieldInfo field = new ProtoFieldInfo(f, prototype);
int fieldNumberZeroBased = field.descriptor().getNumber() - 1;
LocalVariable fieldPresenceVar = fieldPresenceVars[fieldNumberZeroBased / Integer.SIZE];
int fieldPreserveVarBitIndex = fieldNumberZeroBased % Integer.SIZE;
// if-statement for checking whether the current JSON field name matches this field, e.g.,
// if (fieldName == String.intern(field.getName())
// || fieldName == String.intern(field.getJsonName()) {
// ...
// } else if ...
stackManipulations.addAll(Arrays.asList(locals.load(LocalVariable.fieldName), new TextConstant(field.descriptor().getJsonName()), new IfRefsEqual(afterNameCheck), locals.load(LocalVariable.fieldName), new TextConstant(field.descriptor().getName()), new IfRefsNotEqual(afterField), new SetJumpTargetLabel(afterNameCheck)));
// Check whether we have already seen this field in the JSON, which is not allowed. e.g.,
// setFieldBitsN = ParseSupport.throwIfFieldAlreadyWritten(
// setFieldBitsN, 0x1 << field.getNumber() % 8);
stackManipulations.addAll(Arrays.asList(locals.load(fieldPresenceVar), IntegerConstant.forValue(0x1 << fieldPreserveVarBitIndex), new TextConstant(field.descriptor().getFullName()), ParseSupport_throwIfFieldAlreadyWritten, locals.store(fieldPresenceVar)));
// ParseSupport.throwIfOneofAlreadyWritten(builder.getSomeOneofCase(), field.getFullName());
if (field.isInOneof()) {
try {
stackManipulations.addAll(Arrays.asList(locals.load(LocalVariable.parser), locals.load(LocalVariable.builder), invoke(builderClass.getDeclaredMethod(field.getOneOfCaseMethodName())), new TextConstant(field.descriptor().getFullName()), IntegerConstant.forValue(mustSkipNull(field.descriptor())), ParseSupport_throwIfOneofAlreadyWritten));
} catch (NoSuchMethodException e) {
throw new IllegalStateException("Could not find oneof case method.", e);
}
}
// }
if (mustSkipNull(field.descriptor())) {
stackManipulations.addAll(Arrays.asList(locals.load(LocalVariable.parser), ParseSupport_checkNull, new IfTrue(beforeReadField)));
}
StackManipulation setValue = setFieldValue(field, beforeReadField, locals, fieldsByName);
stackManipulations.add(setValue);
stackManipulations.add(new SetJumpTargetLabel(afterField));
}
if (ignoringUnknownFields) {
// If we found no corresponding field number, jump back to the beginning of the while loop.
stackManipulations.add(new Goto(beforeReadField));
} else {
// If we found no corresponding field number, throw an exception.
stackManipulations.addAll(Arrays.asList(locals.load(LocalVariable.fieldName), new TextConstant(descriptor.getFullName()), ParseSupport_throwIfUnknownField));
}
// End of the field processing while loop.
stackManipulations.add(new SetJumpTargetLabel(finished));
stackManipulations.add(MethodReturn.VOID);
StackManipulation.Size operandStackSize = new StackManipulation.Compound(stackManipulations).apply(methodVisitor, implementationContext);
return new Size(operandStackSize.getMaximalSize(), locals.stackSize());
}
use of org.curioswitch.common.protobuf.json.bytebuddy.SetJumpTargetLabel in project curiostack by curioswitch.
the class DoParse method setMapFieldValue.
/**
* Returns the {@link StackManipulation} for setting the value of a map field.
*
* <p>Roughly equivalent to:
*
* <pre>{@code
* ParseSupport.parseObjectStart(parser);
* while (!ParseSupport.checkObjectEnd(parser.currentToken())) {
* builder.putFoo(readKey(), readValue());
* }
* }</pre>
*/
private StackManipulation setMapFieldValue(ProtoFieldInfo info, Label beforeReadField, LocalVariables<LocalVariable> locals, Map<String, FieldDescription> fieldsByName) {
final StackManipulation setConcreteValue = invoke(info.setValueMethod());
final StackManipulation setMapEntry;
if (info.valueJavaType() == JavaType.MESSAGE) {
setMapEntry = new StackManipulation.Compound(TypeCasting.to(new ForLoadedType(info.javaClass())), setConcreteValue);
} else {
setMapEntry = setConcreteValue;
}
Label mapStart = new Label();
Label afterSet = new Label();
StackManipulation.Compound beforeReadKey = new StackManipulation.Compound(locals.load(LocalVariable.parser), ParseSupport_parseObjectStart, new SetJumpTargetLabel(mapStart), locals.load(LocalVariable.parser), Parser_currentToken, ParseSupport_checkObjectEnd, new IfTrue(beforeReadField));
StackManipulation.Compound setValueAndPrepareForNext = new StackManipulation.Compound(setMapEntry, Removal.SINGLE, new SetJumpTargetLabel(afterSet), locals.load(LocalVariable.parser), Parser_nextToken, Removal.SINGLE, new Goto(mapStart));
if (info.valueType() == Type.ENUM) {
// We special-case enum since we may need to skip unknown values.
final LocalVariable keyVar;
switch(info.mapKeyField().valueJavaType()) {
case INT:
keyVar = LocalVariable.intMapKey;
break;
case LONG:
keyVar = LocalVariable.longMapKey;
break;
case BOOLEAN:
keyVar = LocalVariable.boolMapKey;
break;
case STRING:
keyVar = LocalVariable.stringMapKey;
break;
default:
throw new IllegalArgumentException("Invalid map key type");
}
return new StackManipulation.Compound(beforeReadKey, locals.load(LocalVariable.parser), readValue(info.mapKeyField(), fieldsByName, locals), locals.store(keyVar), locals.load(LocalVariable.parser), Parser_nextToken, Removal.SINGLE, locals.load(LocalVariable.parser), readValue(info, fieldsByName, locals), locals.store(LocalVariable.intvalue), locals.load(LocalVariable.intvalue), IntegerConstant.forValue(-1), new IfEqual(int.class, afterSet), locals.load(LocalVariable.builder), locals.load(keyVar), locals.load(LocalVariable.intvalue), setValueAndPrepareForNext);
} else {
return new StackManipulation.Compound(beforeReadKey, locals.load(LocalVariable.builder), locals.load(LocalVariable.parser), readValue(info.mapKeyField(), fieldsByName, locals), locals.load(LocalVariable.parser), Parser_nextToken, Removal.SINGLE, locals.load(LocalVariable.parser), readValue(info, fieldsByName, locals), setValueAndPrepareForNext);
}
}
use of org.curioswitch.common.protobuf.json.bytebuddy.SetJumpTargetLabel in project curiostack by curioswitch.
the class DoWrite method apply.
@Override
public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
Map<String, FieldDescription> fieldsByName = CodeGenUtil.fieldsByName(implementationContext);
List<StackManipulation> stackManipulations = new ArrayList<>();
final StackManipulation getDefaultInstance;
try {
getDefaultInstance = invoke(messageClass.getDeclaredMethod("getDefaultInstance"));
} catch (NoSuchMethodException e) {
throw new IllegalStateException("Could not find getDefaultInstance on a Message class.");
}
LocalVariables<LocalVariable> locals = LocalVariables.builderForMethod(instrumentedMethod, LocalVariable.values()).add(Iterator.class, LocalVariable.iterator).add(Map.Entry.class, LocalVariable.entry).build();
stackManipulations.add(locals.initialize());
// based on the includeDefaults parameter.
for (FieldDescriptor f : CodeGenUtil.sorted(descriptor.getFields())) {
ProtoFieldInfo field = new ProtoFieldInfo(f, prototype);
StackManipulation getValue = new StackManipulation.Compound(locals.load(LocalVariable.message), invoke(field.getValueMethod()));
Label afterSerializeField = new Label();
// }
if (!includeDefaults || // one-of).
field.isInOneof() || // a message has itself as a sub-field.
(field.descriptor().isOptional() && field.valueJavaType() == JavaType.MESSAGE)) {
stackManipulations.add(checkDefaultValue(field, locals, getValue, getDefaultInstance, afterSerializeField));
}
stackManipulations.addAll(Arrays.asList(locals.load(LocalVariable.gen), FieldAccess.forField(fieldsByName.get(CodeGenUtil.fieldNameForSerializedFieldName(field))).read(), JsonGenerator_writeFieldName_SerializableString));
// gen.writeEndObject();
if (field.isMapField()) {
final StackManipulation keyToString;
switch(field.mapKeyField().descriptor().getType()) {
case INT32:
case SINT32:
case SFIXED32:
keyToString = Integer_toString;
break;
case INT64:
case SINT64:
case SFIXED64:
keyToString = Long_toString;
break;
case BOOL:
keyToString = Boolean_toString;
break;
case UINT32:
case FIXED32:
keyToString = new StackManipulation.Compound(SerializeSupport_normalizeUnsignedInt32, Long_toString);
break;
case UINT64:
case FIXED64:
keyToString = SerializeSupport_normalizeUnsignedInt64;
break;
case STRING:
keyToString = Trivial.INSTANCE;
break;
default:
throw new IllegalStateException("Unexpected map key type: " + field.mapKeyField().descriptor().getType());
}
final Label loopStart = new Label();
final Label loopEnd = new Label();
final StackManipulation printValue = printValue(fieldsByName, field);
final StackManipulation printMapFieldValue = new StackManipulation.Compound(locals.load(LocalVariable.gen), JsonGenerator_writeStartObject, getValue, IntegerConstant.forValue(sortingMapKeys), IntegerConstant.forValue(field.mapKeyField().valueType() == Type.STRING), SerializeSupport_mapIterator, locals.store(LocalVariable.iterator), new SetJumpTargetLabel(loopStart), locals.load(LocalVariable.iterator), Iterator_hasNext, new IfFalse(loopEnd), locals.load(LocalVariable.iterator), Iterator_next, TypeCasting.to(new ForLoadedType(Entry.class)), locals.store(LocalVariable.entry), locals.load(LocalVariable.gen), locals.load(LocalVariable.entry), Map_Entry_getKey, unbox(field.mapKeyField()), keyToString, JsonGenerator_writeFieldName_String, locals.load(LocalVariable.entry), Map_Entry_getValue, unbox(field.valueField()), locals.load(LocalVariable.gen), printValue, new Goto(loopStart), new SetJumpTargetLabel(loopEnd), locals.load(LocalVariable.gen), JsonGenerator_writeEndObject);
stackManipulations.add(printMapFieldValue);
} else {
// Simply calls the SerializeSupport method that prints out this field. Any iteration will
// be handled there.
//
// e.g.,
// SerializeSupport.printUnsignedInt32(message.getFoo());
// SerializeSupport.printRepeatedString(message.getBar());
final StackManipulation printValue = printValue(fieldsByName, field);
stackManipulations.addAll(Arrays.asList(getValue, locals.load(LocalVariable.gen), printValue));
}
stackManipulations.add(new SetJumpTargetLabel(afterSerializeField));
}
stackManipulations.add(MethodReturn.VOID);
StackManipulation.Size operandStackSize = new StackManipulation.Compound(stackManipulations).apply(methodVisitor, implementationContext);
return new Size(operandStackSize.getMaximalSize(), locals.stackSize());
}
Aggregations