@@ -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