Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allows the binary reader to avoid allocating PresenceBitmaps when a macro signature has less than 5 required parameters. #1032

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions src/main/java/com/amazon/ion/impl/IonCursorBinary.java
Original file line number Diff line number Diff line change
Expand Up @@ -1910,18 +1910,16 @@ private boolean slowIsDelimitedEnd_1_1() {
* @return the presence bitmap.
*/
protected PresenceBitmap loadPresenceBitmap(List<Macro.Parameter> signature) {
// TODO performance: reuse or pool the presence bitmaps. Ideally, it would not be necessary to allocate them
// at all, but especially not when an invocation does not even have an argument encoding bitmap.
PresenceBitmap presenceBitmap = new PresenceBitmap();
presenceBitmap.initialize(signature);
// TODO performance: reuse or pool the presence bitmaps.
// Note: when there is no AEB, the following initializes the presence bitmap to "EXPRESSION" for each parameter.
PresenceBitmap presenceBitmap = PresenceBitmap.create(signature);
if (presenceBitmap.getByteSize() > 0) {
if (fillArgumentEncodingBitmap(presenceBitmap.getByteSize()) == IonCursor.Event.NEEDS_DATA) {
throw new UnsupportedOperationException("TODO: support continuable parsing of AEBs.");
}
presenceBitmap.readFrom(buffer, (int) valueMarker.startIndex);
presenceBitmap.validate();
}
// Note: when there is no AEB, the following initializes the presence bitmap to "EXPRESSION" for each parameter.
presenceBitmap.readFrom(buffer, (int) valueMarker.startIndex);
presenceBitmap.validate();
return presenceBitmap;
}

Expand Down
57 changes: 47 additions & 10 deletions src/main/java/com/amazon/ion/impl/bin/PresenceBitmap.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,15 @@ import com.amazon.ion.impl.macro.Macro.*
* TODO: Consider whether we can "compile" a specific function that can read the presence bits when we compile a macro.
* That _might_ be more efficient than this approach.
*/
internal class PresenceBitmap {
internal class PresenceBitmap(
var signature: List<Parameter>,
/** The number of parameters for which presence bits must be written. */
private var size: Int,
/** The total number of parameters in the macro signature */
var totalParameterCount: Int
) {

constructor() : this(emptyList(), 0, 0)

companion object {
const val VOID = 0b00L
Expand All @@ -61,17 +69,45 @@ internal class PresenceBitmap {
private const val PB_BITS_PER_SLOT = 2

const val MAX_SUPPORTED_PARAMETERS = PB_SLOTS_PER_LONG * 4
}

var signature: List<Parameter> = emptyList()
private set
private val ZERO_PARAMETERS: PresenceBitmap = allRequired(0)
private val ONE_REQUIRED_PARAMETER: PresenceBitmap = allRequired(1)
private val TWO_REQUIRED_PARAMETERS: PresenceBitmap = allRequired(2)
private val THREE_REQUIRED_PARAMETERS: PresenceBitmap = allRequired(3)
private val FOUR_REQUIRED_PARAMETERS: PresenceBitmap = allRequired(4)

/** The number of parameters for which presence bits must be written. */
private var size: Int = 0
/** Creates a PresenceBitmap for the given number of required parameters */
private fun allRequired(numberOfParameters: Int): PresenceBitmap {
if (numberOfParameters > MAX_SUPPORTED_PARAMETERS) throw IonException("Macros with more than 128 parameters are not supported by this implementation.")
val bitmap = PresenceBitmap(emptyList(), 0, numberOfParameters)
for (i in 0 until numberOfParameters) {
bitmap.setUnchecked(i, EXPRESSION)
}
return bitmap
}

/** The total number of parameters in the macro signature */
val totalParameterCount: Int
get() = signature.size
/** Creates or reuses a [PresenceBitmap] for the given signature. */
@JvmStatic
fun create(signature: List<Parameter>): PresenceBitmap {
if (signature.size > MAX_SUPPORTED_PARAMETERS) throw IonException("Macros with more than 128 parameters are not supported by this implementation.")
// Calculate the actual number of presence bits that will be encoded for the given signature.
val nonRequiredParametersCount = signature.count { it.cardinality != ParameterCardinality.ExactlyOne }
val usePresenceBits = nonRequiredParametersCount > PRESENCE_BITS_SIZE_THRESHOLD || signature.any { it.type.taglessEncodingKind != null }
val size = if (usePresenceBits) nonRequiredParametersCount else 0
return if (size > 0) {
PresenceBitmap(signature, nonRequiredParametersCount, signature.size)
} else {
when (signature.size) {
0 -> ZERO_PARAMETERS
1 -> ONE_REQUIRED_PARAMETER
2 -> TWO_REQUIRED_PARAMETERS
3 -> THREE_REQUIRED_PARAMETERS
4 -> FOUR_REQUIRED_PARAMETERS
else -> allRequired(signature.size)
}
}
}
}

/** The first 32 presence bits slots */
private var a: Long = 0
Expand All @@ -86,7 +122,7 @@ internal class PresenceBitmap {
val byteSize: Int
get() = size divideByRoundingUp PB_SLOTS_PER_BYTE

/** Resets this [PresenceBitmap] for the given [macro]. */
/** Resets this [PresenceBitmap] for the given signature. */
fun initialize(signature: List<Parameter>) {
if (signature.size > MAX_SUPPORTED_PARAMETERS) throw IonException("Macros with more than 128 parameters are not supported by this implementation.")
this.signature = signature
Expand All @@ -99,6 +135,7 @@ internal class PresenceBitmap {
val nonRequiredParametersCount = signature.count { it.cardinality != ParameterCardinality.ExactlyOne }
val usePresenceBits = nonRequiredParametersCount > PRESENCE_BITS_SIZE_THRESHOLD || signature.any { it.type.taglessEncodingKind != null }
size = if (usePresenceBits) nonRequiredParametersCount else 0
totalParameterCount = signature.size
}

/**
Expand Down
Loading