Skip to content

Commit 036fbb0

Browse files
committed
Do not optimize URLs with query strings and switch to interleaved arrays in ArrayPropertyGetter
1 parent 6c8575f commit 036fbb0

3 files changed

Lines changed: 30 additions & 12 deletions

File tree

rulesengine/src/main/java/software/amazon/smithy/java/rulesengine/ArrayPropertyGetter.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@
66
package software.amazon.smithy.java.rulesengine;
77

88
/**
9-
* Lightweight PropertyGetter backed by parallel key/value arrays.
9+
* Lightweight PropertyGetter backed by an interleaved value/key array.
10+
* Layout: [value0, key0, value1, key1, ...]. Keys are at odd indices.
1011
* More efficient than Map for small fixed-key lookups (linear scan beats hashing for ~4 entries).
1112
*/
12-
record ArrayPropertyGetter(String[] keys, Object[] values) implements PropertyGetter {
13+
record ArrayPropertyGetter(Object[] data) implements PropertyGetter {
1314
@Override
1415
public Object getProperty(String name) {
15-
for (int i = 0; i < keys.length; i++) {
16-
if (name.equals(keys[i])) {
17-
return values[i];
16+
for (int i = 1; i < data.length; i += 2) {
17+
if (name.equals(data[i])) {
18+
return data[i - 1];
1819
}
1920
}
2021
return null;

rulesengine/src/main/java/software/amazon/smithy/java/rulesengine/BytecodeCompiler.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,12 @@ private void compileEndpointUrl(Expression urlExpression) {
180180
var parts = template.getParts();
181181
if (parts.size() > 1 && parts.getFirst() instanceof Template.Literal firstLit) {
182182
String firstStr = firstLit.toString();
183+
// Bail out if any literal part contains characters that indicate
184+
// query strings or userInfo — these need full URI.create() parsing.
185+
if (containsUriSpecialChars(parts)) {
186+
compileExpression(urlExpression);
187+
return;
188+
}
183189
int schemeEnd = firstStr.indexOf("://");
184190
if (schemeEnd > 0) {
185191
String scheme = firstStr.substring(0, schemeEnd);
@@ -255,6 +261,18 @@ private void compileEndpointUrl(Expression urlExpression) {
255261
compileExpression(urlExpression);
256262
}
257263

264+
private static boolean containsUriSpecialChars(List<Template.Part> parts) {
265+
for (var part : parts) {
266+
if (part instanceof Template.Literal lit) {
267+
String s = lit.toString();
268+
if (s.indexOf('?') >= 0 || s.indexOf('@') >= 0) {
269+
return true;
270+
}
271+
}
272+
}
273+
return false;
274+
}
275+
258276
private void compileErrorRule(ErrorRule rule) {
259277
compileExpression(rule.getError());
260278
writer.writeByte(Opcodes.RETURN_ERROR);

rulesengine/src/main/java/software/amazon/smithy/java/rulesengine/BytecodeEvaluator.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -285,13 +285,12 @@ private Object runLoop(byte[] instructions, RulesFunction[] functions, Object[]
285285
}
286286
case Opcodes.STRUCTN -> {
287287
var size = instructions[pc++] & 0xFF;
288-
var keys = new String[size];
289-
var values = new Object[size];
290-
for (var i = 0; i < size; i++) {
291-
keys[i] = (String) stack[--stackPosition];
292-
values[i] = stack[--stackPosition];
293-
}
294-
push(new ArrayPropertyGetter(keys, values));
288+
int totalSlots = size * 2;
289+
int base = stackPosition - totalSlots;
290+
var data = new Object[totalSlots];
291+
System.arraycopy(stack, base, data, 0, totalSlots);
292+
stack[base] = new ArrayPropertyGetter(data);
293+
stackPosition = base + 1;
295294
}
296295
case Opcodes.RESOLVE_TEMPLATE -> {
297296
int argCount = instructions[pc++] & 0xFF;

0 commit comments

Comments
 (0)