Skip to content

Commit 0269d85

Browse files
committed
perf(endpoints): Add peephole optimizations to endpoint resolution codegen
Add compile-time peephole optimizations to both BDD and Rules endpoint resolver code generation that eliminate unnecessary allocations and method dispatch overhead: 1. coalesce+substring → startsWith/endsWith/regionMatches 2. ite(cond, a, b) → inline ternary (cond ? a : b) 3. coalesce(boolExpr, default) → inline null-check 4. stringEquals → .equals() unconditionally 5. Dead null-check elimination on ite assigns 6. Endpoint.of(EndpointUrl) zero-attribute factory 7. isValidHostLabel → isValidHostLabelSingle/Multi specialization 8. StringConcatExpression parenthesization for .equals() source
1 parent d5f508e commit 0269d85

10 files changed

Lines changed: 761 additions & 18 deletions

File tree

codegen/src/main/java/software/amazon/awssdk/codegen/poet/rules2/CodeGeneratorVisitor.java

Lines changed: 157 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ public Void visitFunctionCallExpression(FunctionCallExpression e) {
109109
builder.add(" == null");
110110
return null;
111111
}
112+
113+
// Peephole-optimized synthetic functions
114+
if (fn.startsWith("__")) {
115+
emitPeepholeOptimized(fn, e.arguments());
116+
return null;
117+
}
118+
112119
RuleFunctionMirror func = typeMirror.resolveFunction(e.name());
113120
builder.add("$T.$L(", func.containingType().type(), func.javaName());
114121
List<RuleExpression> args = e.arguments();
@@ -124,9 +131,152 @@ public Void visitFunctionCallExpression(FunctionCallExpression e) {
124131
return null;
125132
}
126133

134+
/**
135+
* Emits peephole-optimized native Java code for synthetic function calls.
136+
* These avoid allocations by using String.startsWith/endsWith/regionMatches
137+
* and inline ternary expressions instead of calling RulesFunctions.
138+
*/
139+
private void emitPeepholeOptimized(String fn, List<RuleExpression> args) {
140+
switch (fn) {
141+
case PrepareForCodegenVisitor.STARTS_WITH:
142+
emitStartsWith(args);
143+
break;
144+
case PrepareForCodegenVisitor.ENDS_WITH:
145+
emitEndsWith(args);
146+
break;
147+
case PrepareForCodegenVisitor.REGION_MATCHES:
148+
emitRegionMatches(args);
149+
break;
150+
case PrepareForCodegenVisitor.ITE:
151+
emitIte(args);
152+
break;
153+
case PrepareForCodegenVisitor.COALESCE_BOOL:
154+
emitCoalesceBoolean(args);
155+
break;
156+
case PrepareForCodegenVisitor.IS_VALID_HOST_LABEL:
157+
emitIsValidHostLabel(args);
158+
break;
159+
default:
160+
throw new IllegalStateException("Unknown peephole function: " + fn);
161+
}
162+
}
163+
164+
/**
165+
* Emits: {@code (str != null && str.startsWith("literal"))}
166+
*/
167+
private void emitStartsWith(List<RuleExpression> args) {
168+
builder.add("(");
169+
args.get(0).accept(this);
170+
builder.add(" != null && ");
171+
args.get(0).accept(this);
172+
builder.add(".startsWith(");
173+
args.get(1).accept(this);
174+
builder.add("))");
175+
}
176+
177+
/**
178+
* Emits: {@code (str != null && str.endsWith("literal"))}
179+
*/
180+
private void emitEndsWith(List<RuleExpression> args) {
181+
builder.add("(");
182+
args.get(0).accept(this);
183+
builder.add(" != null && ");
184+
args.get(0).accept(this);
185+
builder.add(".endsWith(");
186+
args.get(1).accept(this);
187+
builder.add("))");
188+
}
189+
190+
/**
191+
* Emits a regionMatches check. Offset can be negative to indicate "from end" (reverse=true).
192+
* <ul>
193+
* <li>Positive offset: {@code (str != null && str.length() >= (offset + litLen)
194+
* && str.regionMatches(offset, "literal", 0, litLen))}</li>
195+
* <li>Negative offset (value = -stopIdx): {@code (str != null && str.length() >= stopIdx
196+
* && str.regionMatches(str.length() - stopIdx, "literal", 0, litLen))}</li>
197+
* </ul>
198+
*/
199+
private void emitRegionMatches(List<RuleExpression> args) {
200+
RuleExpression strExpr = args.get(0);
201+
int offset = ((LiteralIntegerExpression) args.get(1)).value();
202+
String literal = ((LiteralStringExpression) args.get(2)).value();
203+
int litLen = literal.length();
204+
205+
builder.add("(");
206+
strExpr.accept(this);
207+
builder.add(" != null && ");
208+
209+
if (offset >= 0) {
210+
// Forward: str.length() >= (offset + litLen) && str.regionMatches(offset, literal, 0, litLen)
211+
strExpr.accept(this);
212+
builder.add(".length() >= $L && ", offset + litLen);
213+
strExpr.accept(this);
214+
builder.add(".regionMatches(");
215+
builder.add("$L, $S, 0, $L", offset, literal, litLen);
216+
builder.add("))");
217+
} else {
218+
// Reverse: offset encodes -(stopIdx). Actual position = str.length() - stopIdx
219+
int stopIdx = -offset;
220+
strExpr.accept(this);
221+
builder.add(".length() >= $L && ", stopIdx);
222+
strExpr.accept(this);
223+
builder.add(".regionMatches(");
224+
strExpr.accept(this);
225+
builder.add(".length() - $L, $S, 0, $L", stopIdx, literal, litLen);
226+
builder.add("))");
227+
}
228+
}
229+
230+
/**
231+
* Emits: {@code (cond ? ifTrue : ifFalse)}
232+
*/
233+
private void emitIte(List<RuleExpression> args) {
234+
builder.add("(");
235+
args.get(0).accept(this);
236+
builder.add(" ? ");
237+
args.get(1).accept(this);
238+
builder.add(" : ");
239+
args.get(2).accept(this);
240+
builder.add(")");
241+
}
242+
243+
/**
244+
* Emits: {@code (expr != null ? expr : defaultValue)}
245+
*/
246+
private void emitCoalesceBoolean(List<RuleExpression> args) {
247+
builder.add("(");
248+
args.get(0).accept(this);
249+
builder.add(" != null ? ");
250+
args.get(0).accept(this);
251+
builder.add(" : ");
252+
args.get(1).accept(this);
253+
builder.add(")");
254+
}
255+
256+
/**
257+
* Emits: {@code RulesFunctions.isValidHostLabelSingle(str)} or
258+
* {@code RulesFunctions.isValidHostLabelMulti(str)}
259+
*/
260+
private void emitIsValidHostLabel(List<RuleExpression> args) {
261+
boolean allowDots = ((LiteralBooleanExpression) args.get(1)).value();
262+
RuleFunctionMirror func = typeMirror.resolveFunction("isValidHostLabel");
263+
builder.add("$T.$L(", func.containingType().type(),
264+
allowDots ? "isValidHostLabelMulti" : "isValidHostLabelSingle");
265+
args.get(0).accept(this);
266+
builder.add(")");
267+
}
268+
127269
@Override
128270
public Void visitMethodCallExpression(MethodCallExpression e) {
271+
// Wrap compound expressions (string concat) in parens to ensure correct binding
272+
boolean needsParens = e.source().kind() == RuleExpression.RuleExpressionKind.STRING_CONCAT;
273+
if (needsParens) {
274+
builder.add("(");
275+
}
129276
e.source().accept(this);
277+
if (needsParens) {
278+
builder.add(")");
279+
}
130280
builder.add(".$L(", e.name());
131281
boolean isFirst = true;
132282
for (RuleExpression arg : e.arguments()) {
@@ -330,10 +480,16 @@ private String callParams(String ruleId) {
330480
public Void visitEndpointExpression(EndpointExpression e) {
331481
Map<String, RuleExpression> properties = e.properties().properties();
332482
boolean hasHeaders = !e.headers().headers().isEmpty();
483+
boolean hasNoAttributes = !hasHeaders && properties.isEmpty();
333484
boolean hasAuthSchemesOnly = !hasHeaders && properties.size() == 1 && properties.containsKey("authSchemes");
334485
boolean hasTwoAttrs = !hasHeaders && properties.size() == 2 && properties.containsKey("authSchemes");
335486

336-
if (hasAuthSchemesOnly) {
487+
if (hasNoAttributes) {
488+
// Most optimized: Endpoint.of(url) — no attributes, no headers, no builder allocation
489+
builder.add("return $T.of(", Endpoint.class);
490+
EndpointUrlCodeEmitter.emit(e.url(), builder, this);
491+
builder.addStatement(")");
492+
} else if (hasAuthSchemesOnly) {
337493
// Optimized: Endpoint.ofAttribute(url, AUTH_SCHEMES, list)
338494
builder.add("return $T.ofAttribute(", Endpoint.class);
339495
EndpointUrlCodeEmitter.emit(e.url(), builder, this);

0 commit comments

Comments
 (0)