Skip to content

Adds some utilities for Ion 1.0 BytecodeGenerators - #1124

Merged
popematt merged 3 commits into
amazon-ion:ion11from
popematt:ion10utils
Oct 15, 2025
Merged

popematt merged 3 commits into
amazon-ion:ion11from
popematt:ion10utils

Conversation

@popematt

Copy link
Copy Markdown
Contributor

Issue #, if available:

None

Description of changes:

Adds some utilities for handling Timestamp and Decimal references in Ion 1.0 BytecodeGenerators, and for converting from Ion 1.0 typeIds to operation kind.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@popematt
popematt requested review from austnwil and tgregg October 15, 2025 00:05
@popematt

Copy link
Copy Markdown
Contributor Author

Looks like I have a spotbugs warning to deal with.

Comment on lines +43 to +65
private fun initOperationKindForType(state: Int): Int {
return when (state) {
in 0x00..0x0E -> OperationKind.UNSET
0x0F -> OperationKind.NULL
0x10, 0x11, 0x1F -> OperationKind.BOOL
in 0x20..0x2F -> OperationKind.INT
in 0x31..0x3F -> OperationKind.INT
in 0x40..0x4F -> OperationKind.FLOAT
in 0x50..0x5F -> OperationKind.DECIMAL
in 0x60..0x6F -> OperationKind.TIMESTAMP
in 0x70..0x7F -> OperationKind.SYMBOL
in 0x80..0x8F -> OperationKind.STRING
in 0x90..0x9F -> OperationKind.CLOB
in 0xA0..0xAF -> OperationKind.BLOB
in 0xB0..0xBF -> OperationKind.LIST
in 0xC0..0xCF -> OperationKind.SEXP
0xD0, in 0xD2..0xDF -> OperationKind.STRUCT
0xE0 -> OperationKind.IVM
in 0xE1..0xEE -> OperationKind.ANNOTATIONS
// Everything else: 12..1E, 30, D1, EF, F0..FF,
else -> OperationKind.UNSET
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are excluding some illegal typeIDs here (int 0 with type code 3, bools that are not true/false/null, null annotation, etc). but there are still some more that you are not excluding:

  • 0x40 with low nibble 0x01-0x03, 0x05-0x07, and 0x09-0x0E are illegal - only L=4 (for FP32), L=8 (FP64), L=0 (0e0) and L=15 (null) are supported for float
  • 0x60 with low nibble 0x00/0x01 is illegal - timestamps require at least offset and year
  • 0xE0 with low nibble 0x01-0x02 is illegal - annotations require the annot_length field, at least one annotation and the value

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!

"0x3E, INT",
"0x3F, INT",
"0x40, FLOAT",
"0x4E, FLOAT",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already mentioned this, 0x4E and some others are technically illegal.

offset
)
} catch (e: IllegalArgumentException) {
println("Timestamp starting at $position")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remember to remove the println if this was for testing

@codecov

codecov Bot commented Oct 15, 2025 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.15205% with 10 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (ion11@be541e2). Learn more about missing BASE report.

Files with missing lines Patch % Lines
...java/com/amazon/ion/bytecode/bin10/TypeIdHelper.kt 93.33% 1 Missing and 3 partials ⚠️
...java/com/amazon/ion/bytecode/bin10/VarIntHelper.kt 88.23% 2 Missing and 2 partials ⚠️
...java/com/amazon/ion/bytecode/bin10/ValueHelpers.kt 97.40% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##             ion11    #1124   +/-   ##
========================================
  Coverage         ?   68.35%           
  Complexity       ?     5868           
========================================
  Files            ?      189           
  Lines            ?    24043           
  Branches         ?     4286           
========================================
  Hits             ?    16435           
  Misses           ?     6302           
  Partials         ?     1306           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@popematt
popematt requested a review from austnwil October 15, 2025 18:50
// @JvmStatic
val TYPE_LENGTHS by lazy { IntArray(256) { initTypeLength(it) } }

// @JvmStatic

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JvmStatic or not?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shoot. 🤦‍♂️


/**
* Given a typeId in the range 0x20..0x3F, returns either -1 or 1.
* This uses some clever bit twiddling to avoid any branching.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love to have some quantification of the benefit as an interesting learning. Not blocking.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a quantification of the benefit. However, I've been trying to minimize hard-to-predict branching. I'll add a TODO to go and benchmark this vs branching later.

}

/**
* Returns a signed integer up to 7 bytes, with an 1 byte integer signifying how many varuint bytes were used in its encoding.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like bad things could happen if the VarInt exceeds 7 bytes, so we probably need to throw if that happens. I know it adds a branch, but I don't know how to avoid it safely. I'd imagine the branch would ~always be predicted correctly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call.

Comment on lines +115 to +116
// TODO: See if we can have a shared set of reusable buffers for this instead of allocating a copy.
val bytes = valueBytes.copyOfRange(p, p + coefficientLength)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One can dream...

@popematt
popematt requested a review from tgregg October 15, 2025 20:27
var length = 2
do {
length++
if (length > 7) throw IonException("VarUInt value is too large")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be fine to put this after the loop.

@austnwil austnwil left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look good!

@popematt
popematt merged commit 405f760 into amazon-ion:ion11 Oct 15, 2025
33 of 36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants