1 /* 2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang.reflect.code.op; 27 28 import java.lang.constant.ClassDesc; 29 import java.lang.reflect.code.*; 30 import java.lang.reflect.code.type.FieldRef; 31 import java.lang.reflect.code.type.MethodRef; 32 import java.lang.reflect.code.type.*; 33 import java.util.*; 34 import java.util.function.Consumer; 35 import java.util.function.Function; 36 import java.util.function.Predicate; 37 38 /** 39 * The top-level operation class for the set of enclosed core operations. 40 * <p> 41 * A code model, produced by the Java compiler from Java program source, may consist of extended operations and core 42 * operations. Such a model represents the same Java program and preserves the program meaning as defined by the 43 * Java Language Specification 44 */ 45 public sealed abstract class CoreOp extends ExternalizableOp { 46 /** 47 * An operation that models a Java expression 48 */ 49 sealed interface JavaExpression permits 50 ArithmeticOperation, 51 ArrayAccessOp.ArrayLoadOp, 52 ArrayAccessOp.ArrayStoreOp, 53 ArrayLengthOp, 54 CastOp, 55 ConvOp, 56 ClosureOp, 57 ConcatOp, 58 ConstantOp, 59 FieldAccessOp.FieldLoadOp, 60 FieldAccessOp.FieldStoreOp, 61 InstanceOfOp, 62 InvokeOp, 63 LambdaOp, 64 NewOp, 65 TestOperation, 66 VarAccessOp.VarLoadOp, 67 VarAccessOp.VarStoreOp, 68 ExtendedOp.JavaConditionalExpressionOp, 69 ExtendedOp.JavaConditionalOp, 70 ExtendedOp.JavaSwitchExpressionOp { 71 } 72 73 /** 74 * An operation that models a Java statement 75 */ 76 sealed interface JavaStatement permits 77 ArrayAccessOp.ArrayStoreOp, 78 AssertOp, 79 FieldAccessOp.FieldStoreOp, 80 InvokeOp, 81 NewOp, 82 ReturnOp, 83 ThrowOp, 84 VarAccessOp.VarStoreOp, 85 VarOp, 86 ExtendedOp.JavaBlockOp, 87 ExtendedOp.JavaDoWhileOp, 88 ExtendedOp.JavaEnhancedForOp, 89 ExtendedOp.JavaForOp, 90 ExtendedOp.JavaIfOp, 91 ExtendedOp.JavaLabelOp, 92 ExtendedOp.JavaLabeledOp, 93 ExtendedOp.JavaTryOp, 94 ExtendedOp.JavaWhileOp, 95 ExtendedOp.JavaYieldOp { 96 } 97 98 // Split string to ensure the name does not get rewritten 99 // when the script copies this source to the jdk.compiler module 100 static final String PACKAGE_NAME = "java.lang" + ".reflect.code"; 101 102 static final String CoreOp_CLASS_NAME = PACKAGE_NAME + "." + CoreOp.class.getSimpleName(); 103 104 protected CoreOp(Op that, CopyContext cc) { 105 super(that, cc); 106 } 107 108 protected CoreOp(String name, List<? extends Value> operands) { 109 super(name, operands); 110 } 111 112 protected CoreOp(ExternalizedOp def) { 113 super(def); 114 } 115 116 /** 117 * The function operation, that can model a Java method declaration. 118 */ 119 @OpFactory.OpDeclaration(FuncOp.NAME) 120 public static final class FuncOp extends CoreOp 121 implements Op.Invokable, Op.Isolated, Op.Lowerable { 122 123 public static class Builder { 124 final Body.Builder ancestorBody; 125 final String funcName; 126 final FunctionType funcType; 127 128 Builder(Body.Builder ancestorBody, String funcName, FunctionType funcType) { 129 this.ancestorBody = ancestorBody; 130 this.funcName = funcName; 131 this.funcType = funcType; 132 } 133 134 public FuncOp body(Consumer<Block.Builder> c) { 135 Body.Builder body = Body.Builder.of(ancestorBody, funcType); 136 c.accept(body.entryBlock()); 137 return new FuncOp(funcName, body); 138 } 139 } 140 141 public static final String NAME = "func"; 142 public static final String ATTRIBUTE_FUNC_NAME = NAME + ".name"; 143 144 final String funcName; 145 final Body body; 146 147 public static FuncOp create(ExternalizedOp def) { 148 if (!def.operands().isEmpty()) { 149 throw new IllegalStateException("Bad op " + def.name()); 150 } 151 152 String funcName = def.extractAttributeValue(ATTRIBUTE_FUNC_NAME, true, 153 v -> switch (v) { 154 case String s -> s; 155 default -> throw new UnsupportedOperationException("Unsupported func name value:" + v); 156 }); 157 return new FuncOp(def, funcName); 158 } 159 160 FuncOp(ExternalizedOp def, String funcName) { 161 super(def); 162 163 this.funcName = funcName; 164 this.body = def.bodyDefinitions().get(0).build(this); 165 } 166 167 FuncOp(FuncOp that, CopyContext cc, OpTransformer oa) { 168 this(that, that.funcName, cc, oa); 169 } 170 171 FuncOp(FuncOp that, String funcName, CopyContext cc, OpTransformer ot) { 172 super(that, cc); 173 174 this.funcName = funcName; 175 this.body = that.body.transform(cc, ot).build(this); 176 } 177 178 @Override 179 public FuncOp transform(CopyContext cc, OpTransformer ot) { 180 return new FuncOp(this, cc, ot); 181 } 182 183 public FuncOp transform(OpTransformer ot) { 184 return new FuncOp(this, CopyContext.create(), ot); 185 } 186 187 public FuncOp transform(String funcName, OpTransformer ot) { 188 return new FuncOp(this, funcName, CopyContext.create(), ot); 189 } 190 191 FuncOp(String funcName, Body.Builder bodyBuilder) { 192 super(NAME, 193 List.of()); 194 195 this.funcName = funcName; 196 this.body = bodyBuilder.build(this); 197 } 198 199 @Override 200 public List<Body> bodies() { 201 return List.of(body); 202 } 203 204 @Override 205 public Map<String, Object> attributes() { 206 HashMap<String, Object> m = new HashMap<>(super.attributes()); 207 m.put("", funcName); 208 return Collections.unmodifiableMap(m); 209 } 210 211 @Override 212 public FunctionType invokableType() { 213 return body.bodyType(); 214 } 215 216 public String funcName() { 217 return funcName; 218 } 219 220 @Override 221 public Body body() { 222 return body; 223 } 224 225 @Override 226 public Block.Builder lower(Block.Builder b, OpTransformer _ignore) { 227 // Isolate body with respect to ancestor transformations 228 // and copy directly without lowering descendant operations 229 b.op(this, OpTransformer.COPYING_TRANSFORMER); 230 return b; 231 } 232 233 @Override 234 public TypeElement resultType() { 235 return JavaType.VOID; 236 } 237 } 238 239 /** 240 * The function call operation, that models a call to a function, by name, declared in the module op that is also an 241 * ancestor of this operation. 242 */ 243 // @@@ stack effects equivalent to the call operation as if the function were a Java method? 244 @OpFactory.OpDeclaration(FuncCallOp.NAME) 245 public static final class FuncCallOp extends CoreOp { 246 public static final String NAME = "func.call"; 247 public static final String ATTRIBUTE_FUNC_NAME = NAME + ".name"; 248 249 final String funcName; 250 final TypeElement resultType; 251 252 public static FuncCallOp create(ExternalizedOp def) { 253 String funcName = def.extractAttributeValue(ATTRIBUTE_FUNC_NAME, true, 254 v -> switch (v) { 255 case String s -> s; 256 default -> throw new UnsupportedOperationException("Unsupported func name value:" + v); 257 }); 258 259 return new FuncCallOp(def, funcName); 260 } 261 262 FuncCallOp(ExternalizedOp def, String funcName) { 263 super(def); 264 265 this.funcName = funcName; 266 this.resultType = def.resultType(); 267 } 268 269 FuncCallOp(FuncCallOp that, CopyContext cc) { 270 super(that, cc); 271 272 this.funcName = that.funcName; 273 this.resultType = that.resultType; 274 } 275 276 @Override 277 public FuncCallOp transform(CopyContext cc, OpTransformer ot) { 278 return new FuncCallOp(this, cc); 279 } 280 281 FuncCallOp(String funcName, TypeElement resultType, List<Value> args) { 282 super(NAME, args); 283 284 this.funcName = funcName; 285 this.resultType = resultType; 286 } 287 288 @Override 289 public Map<String, Object> attributes() { 290 HashMap<String, Object> m = new HashMap<>(super.attributes()); 291 m.put("", funcName); 292 return Collections.unmodifiableMap(m); 293 } 294 295 public String funcName() { 296 return funcName; 297 } 298 299 @Override 300 public TypeElement resultType() { 301 return resultType; 302 } 303 } 304 305 /** 306 * The module operation, modeling a collection of functions, 307 * and creating a symbol table of function name to function 308 */ 309 @OpFactory.OpDeclaration(ModuleOp.NAME) 310 public static final class ModuleOp extends CoreOp 311 implements Op.Isolated { 312 313 public static final String NAME = "module"; 314 315 final Map<String, FuncOp> table; 316 final Body body; 317 318 public static ModuleOp create(ExternalizedOp def) { 319 if (!def.operands().isEmpty()) { 320 throw new IllegalStateException("Bad op " + def.name()); 321 } 322 323 return new ModuleOp(def); 324 } 325 326 ModuleOp(ExternalizedOp def) { 327 super(def); 328 329 this.body = def.bodyDefinitions().get(0).build(this); 330 this.table = createTable(body); 331 } 332 333 ModuleOp(ModuleOp that, CopyContext cc, OpTransformer ot) { 334 super(that, cc); 335 336 this.body = that.body.transform(cc, ot).build(this); 337 this.table = createTable(body); 338 } 339 340 static Map<String, FuncOp> createTable(Body body) { 341 Map<String, FuncOp> table = new HashMap<>(); 342 for (var op : body.entryBlock().ops()) { 343 if (op instanceof FuncOp fop) { 344 table.put(fop.funcName(), fop); 345 } else { 346 throw new IllegalArgumentException("Bad operation in module: " + op); 347 } 348 } 349 return Collections.unmodifiableMap(table); 350 } 351 352 @Override 353 public ModuleOp transform(CopyContext cc, OpTransformer ot) { 354 return new ModuleOp(this, cc, ot); 355 } 356 357 public ModuleOp transform(OpTransformer ot) { 358 return new ModuleOp(this, CopyContext.create(), ot); 359 } 360 361 ModuleOp(List<FuncOp> functions) { 362 super(NAME, 363 List.of()); 364 365 Body.Builder bodyC = Body.Builder.of(null, FunctionType.VOID); 366 Block.Builder entryBlock = bodyC.entryBlock(); 367 Map<String, FuncOp> table = new HashMap<>(); 368 for (FuncOp f : functions) { 369 entryBlock.op(f); 370 table.put(f.funcName(), f); 371 } 372 this.table = Collections.unmodifiableMap(table); 373 this.body = bodyC.build(this); 374 } 375 376 @Override 377 public List<Body> bodies() { 378 return List.of(body); 379 } 380 381 public Map<String, FuncOp> functionTable() { 382 return table; 383 } 384 385 @Override 386 public TypeElement resultType() { 387 return JavaType.VOID; 388 } 389 } 390 391 /** 392 * The quoted operation, that models the quoting of an operation. 393 */ 394 @OpFactory.OpDeclaration(QuotedOp.NAME) 395 public static final class QuotedOp extends CoreOp 396 implements Op.Nested, Op.Lowerable, Op.Pure { 397 public static final String NAME = "quoted"; 398 399 // Type name must be the same in the java.base and jdk.compiler module 400 static final String Quoted_CLASS_NAME = PACKAGE_NAME + 401 "." + Quoted.class.getSimpleName(); 402 public static final JavaType QUOTED_TYPE = JavaType.type(ClassDesc.of(Quoted_CLASS_NAME)); 403 404 final Body quotedBody; 405 406 final Op quotedOp; 407 408 public QuotedOp(ExternalizedOp def) { 409 super(def); 410 411 this.quotedBody = def.bodyDefinitions().get(0).build(this); 412 413 if (quotedBody.entryBlock().terminatingOp() instanceof YieldOp brk && 414 brk.yieldValue() instanceof Result quotedOpResult) { 415 this.quotedOp = quotedOpResult.op(); 416 } else { 417 throw new IllegalArgumentException(); 418 } 419 } 420 421 QuotedOp(QuotedOp that, CopyContext cc, OpTransformer ot) { 422 super(that, cc); 423 424 this.quotedBody = that.quotedBody.transform(cc, ot).build(this); 425 this.quotedOp = that.quotedOp; 426 } 427 428 @Override 429 public QuotedOp transform(CopyContext cc, OpTransformer ot) { 430 return new QuotedOp(this, cc, ot); 431 } 432 433 QuotedOp(Body.Builder bodyC) { 434 super(NAME, 435 List.of()); 436 437 this.quotedBody = bodyC.build(this); 438 if (quotedBody.blocks().size() > 1) { 439 throw new IllegalArgumentException(); 440 } 441 if (!(quotedBody.entryBlock().terminatingOp() instanceof YieldOp yop)) { 442 throw new IllegalArgumentException(); 443 } 444 if (!(yop.yieldValue() instanceof Result r)) { 445 throw new IllegalArgumentException(); 446 } 447 this.quotedOp = r.op(); 448 } 449 450 @Override 451 public List<Body> bodies() { 452 return List.of(quotedBody); 453 } 454 455 public Op quotedOp() { 456 return quotedOp; 457 } 458 459 @Override 460 public List<Value> capturedValues() { 461 return quotedBody.capturedValues(); 462 } 463 464 @Override 465 public Block.Builder lower(Block.Builder b, OpTransformer _ignore) { 466 // Isolate body with respect to ancestor transformations 467 // and copy directly without lowering descendant operations 468 b.op(this, OpTransformer.COPYING_TRANSFORMER); 469 return b; 470 } 471 472 @Override 473 public TypeElement resultType() { 474 return QUOTED_TYPE; 475 } 476 } 477 478 /** 479 * The lambda operation, that can model a Java lambda expression. 480 */ 481 @OpFactory.OpDeclaration(LambdaOp.NAME) 482 public static final class LambdaOp extends CoreOp 483 implements Op.Invokable, Op.Lowerable, JavaExpression { 484 485 public static class Builder { 486 final Body.Builder ancestorBody; 487 final FunctionType funcType; 488 final TypeElement functionalInterface; 489 490 Builder(Body.Builder ancestorBody, FunctionType funcType, TypeElement functionalInterface) { 491 this.ancestorBody = ancestorBody; 492 this.funcType = funcType; 493 this.functionalInterface = functionalInterface; 494 } 495 496 public LambdaOp body(Consumer<Block.Builder> c) { 497 Body.Builder body = Body.Builder.of(ancestorBody, funcType); 498 c.accept(body.entryBlock()); 499 return new LambdaOp(functionalInterface, body); 500 } 501 } 502 503 public static final String NAME = "lambda"; 504 505 final TypeElement functionalInterface; 506 final Body body; 507 508 public LambdaOp(ExternalizedOp def) { 509 super(def); 510 511 this.functionalInterface = def.resultType(); 512 this.body = def.bodyDefinitions().get(0).build(this); 513 } 514 515 LambdaOp(LambdaOp that, CopyContext cc, OpTransformer ot) { 516 super(that, cc); 517 518 this.functionalInterface = that.functionalInterface; 519 this.body = that.body.transform(cc, ot).build(this); 520 } 521 522 @Override 523 public LambdaOp transform(CopyContext cc, OpTransformer ot) { 524 return new LambdaOp(this, cc, ot); 525 } 526 527 LambdaOp(TypeElement functionalInterface, Body.Builder bodyC) { 528 super(NAME, 529 List.of()); 530 531 this.functionalInterface = functionalInterface; 532 this.body = bodyC.build(this); 533 } 534 535 @Override 536 public List<Body> bodies() { 537 return List.of(body); 538 } 539 540 @Override 541 public FunctionType invokableType() { 542 return body.bodyType(); 543 } 544 545 public TypeElement functionalInterface() { 546 return functionalInterface; 547 } 548 549 @Override 550 public Body body() { 551 return body; 552 } 553 554 @Override 555 public List<Value> capturedValues() { 556 return body.capturedValues(); 557 } 558 559 @Override 560 public Block.Builder lower(Block.Builder b, OpTransformer _ignore) { 561 // Isolate body with respect to ancestor transformations 562 b.op(this, OpTransformer.LOWERING_TRANSFORMER); 563 return b; 564 } 565 566 @Override 567 public TypeElement resultType() { 568 return functionalInterface(); 569 } 570 571 /** 572 * Determines if this lambda operation could have originated from a 573 * method reference declared in Java source code. 574 * <p> 575 * Such a lambda operation is one with the following constraints: 576 * <ol> 577 * <li>Zero or one captured value (assuming correspondence to the {@code this} variable). 578 * <li>A body with only one (entry) block that contains only variable declaration 579 * operations, variable load operations, invoke operations to box or unbox 580 * primitive values, a single invoke operation to the method that is 581 * referenced, and a return operation. 582 * <li>if the return operation returns a non-void result then that result is, 583 * or uniquely depends on, the result of the referencing invoke operation. 584 * <li>If the lambda operation captures one value then the first operand corresponds 585 * to captured the value, and subsequent operands of the referencing invocation 586 * operation are, or uniquely depend on, the lambda operation's parameters, in order. 587 * Otherwise, the first and subsequent operands of the referencing invocation 588 * operation are, or uniquely depend on, the lambda operation's parameters, in order. 589 * </ol> 590 * A value, V2, uniquely depends on another value, V1, if the graph of what V2 depends on 591 * contains only nodes with single edges terminating in V1, and the graph of what depends on V1 592 * is bidirectionally equal to the graph of what V2 depends on. 593 * 594 * @return the invocation operation to the method referenced by the lambda 595 * operation, otherwise empty. 596 */ 597 public Optional<InvokeOp> methodReference() { 598 // Single block 599 if (body().blocks().size() > 1) { 600 return Optional.empty(); 601 } 602 603 // Zero or one (this) capture 604 List<Value> cvs = capturedValues(); 605 if (cvs.size() > 1) { 606 return Optional.empty(); 607 } 608 609 Map<Value, Value> valueMapping = new HashMap<>(); 610 CoreOp.InvokeOp methodRefInvokeOp = extractMethodInvoke(valueMapping, body().entryBlock().ops()); 611 if (methodRefInvokeOp == null) { 612 return Optional.empty(); 613 } 614 615 // Lambda's parameters map in encounter order with the invocation's operands 616 List<Value> lambdaParameters = new ArrayList<>(); 617 if (cvs.size() == 1) { 618 lambdaParameters.add(cvs.getFirst()); 619 } 620 lambdaParameters.addAll(parameters()); 621 List<Value> methodRefOperands = methodRefInvokeOp.operands().stream().map(valueMapping::get).toList(); 622 if (!lambdaParameters.equals(methodRefOperands)) { 623 return Optional.empty(); 624 } 625 626 return Optional.of(methodRefInvokeOp); 627 } 628 629 static CoreOp.InvokeOp extractMethodInvoke(Map<Value, Value> valueMapping, List<Op> ops) { 630 CoreOp.InvokeOp methodRefInvokeOp = null; 631 for (Op op : ops) { 632 switch (op) { 633 case CoreOp.VarOp varOp -> { 634 if (isValueUsedWithOp(varOp.result(), o -> o instanceof CoreOp.VarAccessOp.VarStoreOp)) { 635 return null; 636 } 637 } 638 case CoreOp.VarAccessOp.VarLoadOp varLoadOp -> { 639 Value v = varLoadOp.varOp().operands().getFirst(); 640 valueMapping.put(varLoadOp.result(), valueMapping.getOrDefault(v, v)); 641 } 642 case CoreOp.InvokeOp iop when isBoxOrUnboxInvocation(iop) -> { 643 Value v = iop.operands().getFirst(); 644 valueMapping.put(iop.result(), valueMapping.getOrDefault(v, v)); 645 } 646 case CoreOp.InvokeOp iop -> { 647 if (methodRefInvokeOp != null) { 648 return null; 649 } 650 651 for (Value o : iop.operands()) { 652 valueMapping.put(o, valueMapping.getOrDefault(o, o)); 653 } 654 methodRefInvokeOp = iop; 655 } 656 case CoreOp.ReturnOp rop -> { 657 if (methodRefInvokeOp == null) { 658 return null; 659 } 660 Value r = rop.returnValue(); 661 if (!(valueMapping.getOrDefault(r, r) instanceof Op.Result invokeResult)) { 662 return null; 663 } 664 if (invokeResult.op() != methodRefInvokeOp) { 665 return null; 666 } 667 assert methodRefInvokeOp.result().uses().size() == 1; 668 } 669 default -> { 670 return null; 671 } 672 } 673 } 674 675 return methodRefInvokeOp; 676 } 677 678 private static boolean isValueUsedWithOp(Value value, Predicate<Op> opPredicate) { 679 for (Op.Result user : value.uses()) { 680 if (opPredicate.test(user.op())) { 681 return true; 682 } 683 } 684 return false; 685 } 686 687 // @@@ Move to functionality on JavaType(s) 688 static final Set<String> UNBOX_NAMES = Set.of( 689 "byteValue", 690 "shortValue", 691 "charValue", 692 "intValue", 693 "longValue", 694 "floatValue", 695 "doubleValue", 696 "booleanValue"); 697 698 private static boolean isBoxOrUnboxInvocation(CoreOp.InvokeOp iop) { 699 MethodRef mr = iop.invokeDescriptor(); 700 return mr.refType() instanceof ClassType ct && ct.unbox().isPresent() && 701 (UNBOX_NAMES.contains(mr.name()) || mr.name().equals("valueOf")); 702 } 703 } 704 705 /** 706 * The closure operation, that can model a structured Java lambda expression 707 * that has no target type (a functional interface). 708 */ 709 @OpFactory.OpDeclaration(ClosureOp.NAME) 710 public static final class ClosureOp extends CoreOp 711 implements Op.Invokable, Op.Lowerable, JavaExpression { 712 713 public static class Builder { 714 final Body.Builder ancestorBody; 715 final FunctionType funcType; 716 717 Builder(Body.Builder ancestorBody, FunctionType funcType) { 718 this.ancestorBody = ancestorBody; 719 this.funcType = funcType; 720 } 721 722 public ClosureOp body(Consumer<Block.Builder> c) { 723 Body.Builder body = Body.Builder.of(ancestorBody, funcType); 724 c.accept(body.entryBlock()); 725 return new ClosureOp(body); 726 } 727 } 728 729 public static final String NAME = "closure"; 730 731 final Body body; 732 733 public ClosureOp(ExternalizedOp def) { 734 super(def); 735 736 this.body = def.bodyDefinitions().get(0).build(this); 737 } 738 739 ClosureOp(ClosureOp that, CopyContext cc, OpTransformer ot) { 740 super(that, cc); 741 742 this.body = that.body.transform(cc, ot).build(this); 743 } 744 745 @Override 746 public ClosureOp transform(CopyContext cc, OpTransformer ot) { 747 return new ClosureOp(this, cc, ot); 748 } 749 750 ClosureOp(Body.Builder bodyC) { 751 super(NAME, 752 List.of()); 753 754 this.body = bodyC.build(this); 755 } 756 757 @Override 758 public List<Body> bodies() { 759 return List.of(body); 760 } 761 762 @Override 763 public FunctionType invokableType() { 764 return body.bodyType(); 765 } 766 767 @Override 768 public Body body() { 769 return body; 770 } 771 772 @Override 773 public List<Value> capturedValues() { 774 return body.capturedValues(); 775 } 776 777 @Override 778 public Block.Builder lower(Block.Builder b, OpTransformer _ignore) { 779 // Isolate body with respect to ancestor transformations 780 b.op(this, OpTransformer.LOWERING_TRANSFORMER); 781 return b; 782 } 783 784 @Override 785 public TypeElement resultType() { 786 return body.bodyType(); 787 } 788 } 789 790 /** 791 * The closure call operation, that models a call to a closure, by reference 792 */ 793 // @@@ stack effects equivalent to the invocation of an SAM of on an instance of an anonymous functional interface 794 // that is the target of the closures lambda expression. 795 @OpFactory.OpDeclaration(ClosureCallOp.NAME) 796 public static final class ClosureCallOp extends CoreOp { 797 public static final String NAME = "closure.call"; 798 799 public ClosureCallOp(ExternalizedOp def) { 800 super(def); 801 } 802 803 ClosureCallOp(ClosureCallOp that, CopyContext cc) { 804 super(that, cc); 805 } 806 807 @Override 808 public ClosureCallOp transform(CopyContext cc, OpTransformer ot) { 809 return new ClosureCallOp(this, cc); 810 } 811 812 ClosureCallOp(List<Value> args) { 813 super(NAME, args); 814 } 815 816 @Override 817 public TypeElement resultType() { 818 FunctionType ft = (FunctionType) operands().getFirst().type(); 819 return ft.returnType(); 820 } 821 } 822 823 /** 824 * The terminating return operation, that can model the Java language return statement. 825 * <p> 826 * This operation exits an isolated body. 827 */ 828 @OpFactory.OpDeclaration(ReturnOp.NAME) 829 public static final class ReturnOp extends CoreOp 830 implements Op.BodyTerminating, JavaStatement { 831 public static final String NAME = "return"; 832 833 public ReturnOp(ExternalizedOp def) { 834 super(def); 835 836 if (def.operands().size() > 1) { 837 throw new IllegalArgumentException("Operation must have zero or one operand " + def.name()); 838 } 839 } 840 841 ReturnOp(ReturnOp that, CopyContext cc) { 842 super(that, cc); 843 } 844 845 @Override 846 public ReturnOp transform(CopyContext cc, OpTransformer ot) { 847 return new ReturnOp(this, cc); 848 } 849 850 ReturnOp() { 851 super(NAME, List.of()); 852 } 853 854 ReturnOp(Value operand) { 855 super(NAME, List.of(operand)); 856 } 857 858 public Value returnValue() { 859 if (operands().size() == 1) { 860 return operands().get(0); 861 } else { 862 // @@@ 863 return null; 864 } 865 } 866 867 @Override 868 public TypeElement resultType() { 869 return JavaType.VOID; 870 } 871 } 872 873 /** 874 * The terminating throw operation, that can model the Java language throw statement. 875 */ 876 @OpFactory.OpDeclaration(ThrowOp.NAME) 877 public static final class ThrowOp extends CoreOp 878 implements Op.BodyTerminating, JavaStatement { 879 public static final String NAME = "throw"; 880 881 public ThrowOp(ExternalizedOp def) { 882 super(def); 883 884 if (def.operands().size() != 1) { 885 throw new IllegalArgumentException("Operation must have one operand " + def.name()); 886 } 887 } 888 889 ThrowOp(ThrowOp that, CopyContext cc) { 890 super(that, cc); 891 } 892 893 @Override 894 public ThrowOp transform(CopyContext cc, OpTransformer ot) { 895 return new ThrowOp(this, cc); 896 } 897 898 ThrowOp(Value e) { 899 super(NAME, List.of(e)); 900 } 901 902 public Value argument() { 903 return operands().get(0); 904 } 905 906 @Override 907 public TypeElement resultType() { 908 return JavaType.VOID; 909 } 910 } 911 912 /** 913 * The assertion operation. Supporting assertions in statement form. 914 */ 915 @OpFactory.OpDeclaration(AssertOp.NAME) 916 public static final class AssertOp extends CoreOp 917 implements Op.Nested, JavaStatement { 918 public static final String NAME = "assert"; 919 public final List<Body> bodies; 920 921 public AssertOp(ExternalizedOp def) { 922 super(def); 923 var bodies = def.bodyDefinitions().stream().map(b -> b.build(this)).toList(); 924 checkBodies(bodies); 925 this.bodies = bodies; 926 } 927 928 public AssertOp(List<Body.Builder> bodies) { 929 super(NAME, List.of()); 930 checkBodies(bodies); 931 this.bodies = bodies.stream().map(b -> b.build(this)).toList(); 932 } 933 934 AssertOp(AssertOp that, CopyContext cc, OpTransformer ot) { 935 936 super(that, cc); 937 this.bodies = that.bodies.stream().map(b -> b.transform(cc, ot).build(this)).toList(); 938 } 939 940 private void checkBodies(List<?> bodies) { 941 if (bodies.size() != 1 && bodies.size() != 2) { 942 throw new IllegalArgumentException("Assert must have one or two bodies."); 943 } 944 } 945 946 @Override 947 public Op transform(CopyContext cc, OpTransformer ot) { 948 return new AssertOp(this, cc, ot); 949 } 950 951 @Override 952 public TypeElement resultType() { 953 return JavaType.VOID; 954 } 955 956 @Override 957 public List<Body> bodies() { 958 return this.bodies; 959 } 960 } 961 962 /** 963 * The terminating unreachable operation. 964 * <p> 965 * This operation models termination that is unreachable. 966 */ 967 @OpFactory.OpDeclaration(UnreachableOp.NAME) 968 public static final class UnreachableOp extends CoreOp 969 implements Op.BodyTerminating { 970 public static final String NAME = "unreachable"; 971 972 public UnreachableOp(ExternalizedOp def) { 973 super(def); 974 975 if (!def.operands().isEmpty()) { 976 throw new IllegalArgumentException("Operation must zero operands " + def.name()); 977 } 978 } 979 980 UnreachableOp(UnreachableOp that, CopyContext cc) { 981 super(that, cc); 982 } 983 984 @Override 985 public UnreachableOp transform(CopyContext cc, OpTransformer ot) { 986 return new UnreachableOp(this, cc); 987 } 988 989 UnreachableOp() { 990 super(NAME, List.of()); 991 } 992 993 @Override 994 public TypeElement resultType() { 995 return JavaType.VOID; 996 } 997 } 998 999 /** 1000 * The terminating yield operation. 1001 * <p> 1002 * This operation models exits from its parent body, yielding at most one value (zero value for yielding unit 1003 * or void) 1004 */ 1005 @OpFactory.OpDeclaration(YieldOp.NAME) 1006 public static final class YieldOp extends CoreOp 1007 implements Op.BodyTerminating { 1008 public static final String NAME = "yield"; 1009 1010 public YieldOp(ExternalizedOp def) { 1011 super(def); 1012 1013 if (def.operands().size() > 1) { 1014 throw new IllegalArgumentException("Operation must have zero or one operand " + def.name()); 1015 } 1016 } 1017 1018 YieldOp(YieldOp that, CopyContext cc) { 1019 super(that, cc); 1020 } 1021 1022 @Override 1023 public YieldOp transform(CopyContext cc, OpTransformer ot) { 1024 return new YieldOp(this, cc); 1025 } 1026 1027 YieldOp() { 1028 super(NAME, List.of()); 1029 } 1030 1031 YieldOp(List<Value> operands) { 1032 super(NAME, operands); 1033 } 1034 1035 public Value yieldValue() { 1036 if (operands().size() == 1) { 1037 return operands().get(0); 1038 } else { 1039 // @@@ 1040 return null; 1041 } 1042 } 1043 1044 @Override 1045 public TypeElement resultType() { 1046 return JavaType.VOID; 1047 } 1048 } 1049 1050 /** 1051 * The terminating unconditional branch operation. 1052 * <p> 1053 * This operation accepts a successor to the next block to branch to. 1054 */ 1055 @OpFactory.OpDeclaration(BranchOp.NAME) 1056 public static final class BranchOp extends CoreOp 1057 implements Op.BlockTerminating { 1058 public static final String NAME = "branch"; 1059 1060 final Block.Reference b; 1061 1062 public BranchOp(ExternalizedOp def) { 1063 super(def); 1064 1065 if (!def.operands().isEmpty() || def.successors().size() != 1) { 1066 throw new IllegalArgumentException("Operation must have zero arguments and one successor" + def.name()); 1067 } 1068 1069 this.b = def.successors().get(0); 1070 } 1071 1072 BranchOp(BranchOp that, CopyContext cc) { 1073 super(that, cc); 1074 1075 this.b = cc.getSuccessorOrCreate(that.b); 1076 } 1077 1078 @Override 1079 public BranchOp transform(CopyContext cc, OpTransformer ot) { 1080 return new BranchOp(this, cc); 1081 } 1082 1083 BranchOp(Block.Reference successor) { 1084 super(NAME, List.of()); 1085 1086 this.b = successor; 1087 } 1088 1089 @Override 1090 public List<Block.Reference> successors() { 1091 return List.of(b); 1092 } 1093 1094 public Block.Reference branch() { 1095 return b; 1096 } 1097 1098 @Override 1099 public TypeElement resultType() { 1100 return JavaType.VOID; 1101 } 1102 } 1103 1104 /** 1105 * The terminating conditional branch operation. 1106 * <p> 1107 * This operation accepts a boolean operand and two successors, the true successor and false successor. 1108 * When the operand is true the true successor is selected, otherwise the false successor is selected. 1109 * The selected successor refers to the next block to branch to. 1110 */ 1111 @OpFactory.OpDeclaration(ConditionalBranchOp.NAME) 1112 public static final class ConditionalBranchOp extends CoreOp 1113 implements Op.BlockTerminating { 1114 public static final String NAME = "cbranch"; 1115 1116 final Block.Reference t; 1117 final Block.Reference f; 1118 1119 public ConditionalBranchOp(ExternalizedOp def) { 1120 super(def); 1121 1122 if (def.operands().size() != 1 || def.successors().size() != 2) { 1123 throw new IllegalArgumentException("Operation must one operand and two successors" + def.name()); 1124 } 1125 1126 this.t = def.successors().get(0); 1127 this.f = def.successors().get(1); 1128 } 1129 1130 ConditionalBranchOp(ConditionalBranchOp that, CopyContext cc) { 1131 super(that, cc); 1132 1133 this.t = cc.getSuccessorOrCreate(that.t); 1134 this.f = cc.getSuccessorOrCreate(that.f); 1135 } 1136 1137 @Override 1138 public ConditionalBranchOp transform(CopyContext cc, OpTransformer ot) { 1139 return new ConditionalBranchOp(this, cc); 1140 } 1141 1142 ConditionalBranchOp(Value p, Block.Reference t, Block.Reference f) { 1143 super(NAME, List.of(p)); 1144 1145 this.t = t; 1146 this.f = f; 1147 } 1148 1149 @Override 1150 public List<Block.Reference> successors() { 1151 return List.of(t, f); 1152 } 1153 1154 public Value predicate() { 1155 return operands().get(0); 1156 } 1157 1158 public Block.Reference trueBranch() { 1159 return t; 1160 } 1161 1162 public Block.Reference falseBranch() { 1163 return f; 1164 } 1165 1166 @Override 1167 public TypeElement resultType() { 1168 return JavaType.VOID; 1169 } 1170 } 1171 1172 /** 1173 * The constant operation, that can model Java language literal and constant expressions. 1174 */ 1175 @OpFactory.OpDeclaration(ConstantOp.NAME) 1176 public static final class ConstantOp extends CoreOp 1177 implements Op.Pure, JavaExpression { 1178 public static final String NAME = "constant"; 1179 1180 public static final String ATTRIBUTE_CONSTANT_VALUE = NAME + ".value"; 1181 1182 final Object value; 1183 final TypeElement type; 1184 1185 public static ConstantOp create(ExternalizedOp def) { 1186 if (!def.operands().isEmpty()) { 1187 throw new IllegalArgumentException("Operation must have zero operands"); 1188 } 1189 1190 Object value = def.extractAttributeValue(ATTRIBUTE_CONSTANT_VALUE, true, 1191 v -> processConstantValue(def.resultType(), v)); 1192 return new ConstantOp(def, value); 1193 } 1194 1195 static Object processConstantValue(TypeElement t, Object value) { 1196 if (t.equals(JavaType.BOOLEAN)) { 1197 if (value instanceof String s) { 1198 return Boolean.valueOf(s); 1199 } else if (value instanceof Boolean) { 1200 return value; 1201 } 1202 } else if (t.equals(JavaType.BYTE)) { 1203 if (value instanceof String s) { 1204 return Byte.valueOf(s); 1205 } else if (value instanceof Number n) { 1206 return n.byteValue(); 1207 } 1208 } else if (t.equals(JavaType.SHORT)) { 1209 if (value instanceof String s) { 1210 return Short.valueOf(s); 1211 } else if (value instanceof Number n) { 1212 return n.shortValue(); 1213 } 1214 } else if (t.equals(JavaType.CHAR)) { 1215 if (value instanceof String s) { 1216 return s.charAt(0); 1217 } else if (value instanceof Character) { 1218 return value; 1219 } 1220 } else if (t.equals(JavaType.INT)) { 1221 if (value instanceof String s) { 1222 return Integer.valueOf(s); 1223 } else if (value instanceof Number n) { 1224 return n.intValue(); 1225 } 1226 } else if (t.equals(JavaType.LONG)) { 1227 if (value instanceof String s) { 1228 return Long.valueOf(s); 1229 } else if (value instanceof Number n) { 1230 return n.longValue(); 1231 } 1232 } else if (t.equals(JavaType.FLOAT)) { 1233 if (value instanceof String s) { 1234 return Float.valueOf(s); 1235 } else if (value instanceof Number n) { 1236 return n.floatValue(); 1237 } 1238 } else if (t.equals(JavaType.DOUBLE)) { 1239 if (value instanceof String s) { 1240 return Double.valueOf(s); 1241 } else if (value instanceof Number n) { 1242 return n.doubleValue(); 1243 } 1244 } else if (t.equals(JavaType.J_L_STRING)) { 1245 return value == NULL_ATTRIBUTE_VALUE ? null : 1246 value.toString(); 1247 } else if (t.equals(JavaType.J_L_CLASS)) { 1248 return value == NULL_ATTRIBUTE_VALUE ? null : JavaType.ofString(value.toString()); 1249 } else if (value == NULL_ATTRIBUTE_VALUE) { 1250 return null; // null constant 1251 } 1252 1253 throw new UnsupportedOperationException("Unsupported constant type and value: " + t + " " + value); 1254 } 1255 1256 ConstantOp(ExternalizedOp def, Object value) { 1257 super(def); 1258 1259 this.type = def.resultType(); 1260 this.value = value; 1261 } 1262 1263 ConstantOp(ConstantOp that, CopyContext cc) { 1264 super(that, cc); 1265 1266 this.type = that.type; 1267 this.value = that.value; 1268 } 1269 1270 @Override 1271 public ConstantOp transform(CopyContext cc, OpTransformer ot) { 1272 return new ConstantOp(this, cc); 1273 } 1274 1275 ConstantOp(TypeElement type, Object value) { 1276 super(NAME, List.of()); 1277 1278 this.type = type; 1279 this.value = value; 1280 } 1281 1282 @Override 1283 public Map<String, Object> attributes() { 1284 HashMap<String, Object> attrs = new HashMap<>(super.attributes()); 1285 attrs.put("", value == null ? NULL_ATTRIBUTE_VALUE : value); 1286 return attrs; 1287 } 1288 1289 public Object value() { 1290 return value; 1291 } 1292 1293 @Override 1294 public TypeElement resultType() { 1295 return type; 1296 } 1297 } 1298 1299 /** 1300 * An operation characteristic indicating the operation's behavior may be emulated using Java reflection. 1301 * A descriptor is derived from or declared by the operation that can be resolved at runtime to 1302 * an instance of a reflective handle or member. That handle or member can be operated on to 1303 * emulate the operation's behavior, specifically as bytecode behavior. 1304 */ 1305 public sealed interface ReflectiveOp { 1306 } 1307 1308 /** 1309 * The invoke operation, that can model Java language method invocation expressions. 1310 */ 1311 @OpFactory.OpDeclaration(InvokeOp.NAME) 1312 public static final class InvokeOp extends CoreOp 1313 implements ReflectiveOp, JavaExpression, JavaStatement { 1314 public static final String NAME = "invoke"; 1315 public static final String ATTRIBUTE_INVOKE_DESCRIPTOR = NAME + ".descriptor"; 1316 1317 final MethodRef invokeDescriptor; 1318 final TypeElement resultType; 1319 1320 public static InvokeOp create(ExternalizedOp def) { 1321 MethodRef invokeDescriptor = def.extractAttributeValue(ATTRIBUTE_INVOKE_DESCRIPTOR, 1322 true, v -> switch (v) { 1323 case String s -> MethodRef.ofString(s); 1324 case MethodRef md -> md; 1325 default -> throw new UnsupportedOperationException("Unsupported invoke descriptor value:" + v); 1326 }); 1327 1328 return new InvokeOp(def, invokeDescriptor); 1329 } 1330 1331 InvokeOp(ExternalizedOp def, MethodRef invokeDescriptor) { 1332 super(def); 1333 1334 this.invokeDescriptor = invokeDescriptor; 1335 this.resultType = def.resultType(); 1336 } 1337 1338 InvokeOp(InvokeOp that, CopyContext cc) { 1339 super(that, cc); 1340 1341 this.invokeDescriptor = that.invokeDescriptor; 1342 this.resultType = that.resultType; 1343 } 1344 1345 @Override 1346 public InvokeOp transform(CopyContext cc, OpTransformer ot) { 1347 return new InvokeOp(this, cc); 1348 } 1349 1350 InvokeOp(MethodRef invokeDescriptor, List<Value> args) { 1351 this(invokeDescriptor.type().returnType(), invokeDescriptor, args); 1352 } 1353 1354 InvokeOp(TypeElement resultType, MethodRef invokeDescriptor, List<Value> args) { 1355 super(NAME, args); 1356 1357 this.invokeDescriptor = invokeDescriptor; 1358 this.resultType = resultType; 1359 } 1360 1361 @Override 1362 public Map<String, Object> attributes() { 1363 HashMap<String, Object> m = new HashMap<>(super.attributes()); 1364 m.put("", invokeDescriptor); 1365 return Collections.unmodifiableMap(m); 1366 } 1367 1368 public MethodRef invokeDescriptor() { 1369 return invokeDescriptor; 1370 } 1371 1372 public boolean hasReceiver() { 1373 return operands().size() != invokeDescriptor().type().parameterTypes().size(); 1374 } 1375 1376 @Override 1377 public TypeElement resultType() { 1378 return resultType; 1379 } 1380 } 1381 1382 /** 1383 * The conversion operation, that can model Java language cast expressions 1384 * for numerical conversion, or such implicit conversion. 1385 */ 1386 @OpFactory.OpDeclaration(ConvOp.NAME) 1387 public static final class ConvOp extends CoreOp 1388 implements Op.Pure, JavaExpression { 1389 public static final String NAME = "conv"; 1390 1391 final TypeElement resultType; 1392 1393 public ConvOp(ExternalizedOp def) { 1394 super(def); 1395 1396 this.resultType = def.resultType(); 1397 } 1398 1399 ConvOp(ConvOp that, CopyContext cc) { 1400 super(that, cc); 1401 1402 this.resultType = that.resultType; 1403 } 1404 1405 @Override 1406 public Op transform(CopyContext cc, OpTransformer ot) { 1407 return new ConvOp(this, cc); 1408 } 1409 1410 ConvOp(TypeElement resultType, Value arg) { 1411 super(NAME, List.of(arg)); 1412 1413 this.resultType = resultType; 1414 } 1415 1416 @Override 1417 public TypeElement resultType() { 1418 return resultType; 1419 } 1420 } 1421 1422 /** 1423 * The new operation, that can models Java language instance creation expressions. 1424 */ 1425 @OpFactory.OpDeclaration(NewOp.NAME) 1426 public static final class NewOp extends CoreOp 1427 implements ReflectiveOp, JavaExpression, JavaStatement { 1428 public static final String NAME = "new"; 1429 public static final String ATTRIBUTE_NEW_DESCRIPTOR = NAME + ".descriptor"; 1430 1431 final FunctionType constructorType; 1432 final TypeElement resultType; 1433 1434 public static NewOp create(ExternalizedOp def) { 1435 FunctionType constructorType = def.extractAttributeValue(ATTRIBUTE_NEW_DESCRIPTOR, true, 1436 v -> switch (v) { 1437 case String s -> { 1438 TypeElement te = CoreTypeFactory.CORE_TYPE_FACTORY 1439 .constructType(TypeElement.ExternalizedTypeElement.ofString(s)); 1440 if (!(te instanceof FunctionType ft)) { 1441 throw new UnsupportedOperationException("Unsupported new descriptor value:" + v); 1442 } 1443 yield ft; 1444 } 1445 case FunctionType ct -> ct; 1446 default -> throw new UnsupportedOperationException("Unsupported new descriptor value:" + v); 1447 }); 1448 return new NewOp(def, constructorType); 1449 } 1450 1451 NewOp(ExternalizedOp def, FunctionType constructorType) { 1452 super(def); 1453 1454 this.constructorType = constructorType; 1455 this.resultType = def.resultType(); 1456 } 1457 1458 NewOp(NewOp that, CopyContext cc) { 1459 super(that, cc); 1460 1461 this.constructorType = that.constructorType; 1462 this.resultType = that.resultType; 1463 } 1464 1465 @Override 1466 public NewOp transform(CopyContext cc, OpTransformer ot) { 1467 return new NewOp(this, cc); 1468 } 1469 1470 NewOp(FunctionType constructorType, List<Value> args) { 1471 this(constructorType.returnType(), constructorType, args); 1472 } 1473 1474 NewOp(TypeElement resultType, FunctionType constructorType, List<Value> args) { 1475 super(NAME, args); 1476 1477 this.constructorType = constructorType; 1478 this.resultType = resultType; 1479 } 1480 1481 @Override 1482 public Map<String, Object> attributes() { 1483 HashMap<String, Object> m = new HashMap<>(super.attributes()); 1484 m.put("", constructorType); 1485 return Collections.unmodifiableMap(m); 1486 } 1487 1488 public TypeElement type() { 1489 return opType().returnType(); 1490 } 1491 1492 public FunctionType constructorType() { 1493 return constructorType; 1494 } 1495 1496 @Override 1497 public TypeElement resultType() { 1498 return resultType; 1499 } 1500 } 1501 1502 /** 1503 * An operation that performs access. 1504 */ 1505 public sealed interface AccessOp { 1506 } 1507 1508 /** 1509 * A field access operation, that can model Java langauge field access expressions. 1510 */ 1511 public sealed abstract static class FieldAccessOp extends CoreOp 1512 implements AccessOp, ReflectiveOp { 1513 public static final String ATTRIBUTE_FIELD_DESCRIPTOR = "field.descriptor"; 1514 1515 final FieldRef fieldDescriptor; 1516 1517 FieldAccessOp(ExternalizedOp def, FieldRef fieldDescriptor) { 1518 super(def); 1519 1520 this.fieldDescriptor = fieldDescriptor; 1521 } 1522 1523 FieldAccessOp(FieldAccessOp that, CopyContext cc) { 1524 super(that, cc); 1525 1526 this.fieldDescriptor = that.fieldDescriptor; 1527 } 1528 1529 FieldAccessOp(String name, List<Value> operands, 1530 FieldRef fieldDescriptor) { 1531 super(name, operands); 1532 1533 this.fieldDescriptor = fieldDescriptor; 1534 } 1535 1536 @Override 1537 public Map<String, Object> attributes() { 1538 HashMap<String, Object> m = new HashMap<>(super.attributes()); 1539 m.put("", fieldDescriptor); 1540 return Collections.unmodifiableMap(m); 1541 } 1542 1543 public final FieldRef fieldDescriptor() { 1544 return fieldDescriptor; 1545 } 1546 1547 /** 1548 * The field load operation, that can model Java language field access expressions combined with load access to 1549 * field instance variables. 1550 */ 1551 @OpFactory.OpDeclaration(FieldLoadOp.NAME) 1552 public static final class FieldLoadOp extends FieldAccessOp 1553 implements Op.Pure, JavaExpression { 1554 public static final String NAME = "field.load"; 1555 1556 final TypeElement resultType; 1557 1558 public static FieldLoadOp create(ExternalizedOp def) { 1559 if (def.operands().size() > 1) { 1560 throw new IllegalArgumentException("Operation must accept zero or one operand"); 1561 } 1562 1563 FieldRef fieldDescriptor = def.extractAttributeValue(ATTRIBUTE_FIELD_DESCRIPTOR, true, 1564 v -> switch (v) { 1565 case String s -> FieldRef.ofString(s); 1566 case FieldRef fd -> fd; 1567 default -> 1568 throw new UnsupportedOperationException("Unsupported field descriptor value:" + v); 1569 }); 1570 return new FieldLoadOp(def, fieldDescriptor); 1571 } 1572 1573 FieldLoadOp(ExternalizedOp opdef, FieldRef fieldDescriptor) { 1574 super(opdef, fieldDescriptor); 1575 1576 resultType = opdef.resultType(); 1577 } 1578 1579 FieldLoadOp(FieldLoadOp that, CopyContext cc) { 1580 super(that, cc); 1581 1582 resultType = that.resultType(); 1583 } 1584 1585 @Override 1586 public FieldLoadOp transform(CopyContext cc, OpTransformer ot) { 1587 return new FieldLoadOp(this, cc); 1588 } 1589 1590 // instance 1591 FieldLoadOp(TypeElement resultType, FieldRef descriptor, Value receiver) { 1592 super(NAME, List.of(receiver), descriptor); 1593 1594 this.resultType = resultType; 1595 } 1596 1597 // static 1598 FieldLoadOp(TypeElement resultType, FieldRef descriptor) { 1599 super(NAME, List.of(), descriptor); 1600 1601 this.resultType = resultType; 1602 } 1603 1604 @Override 1605 public TypeElement resultType() { 1606 return resultType; 1607 } 1608 } 1609 1610 /** 1611 * The field store operation, that can model Java language field access expressions combined with store access 1612 * to field instance variables. 1613 */ 1614 @OpFactory.OpDeclaration(FieldStoreOp.NAME) 1615 public static final class FieldStoreOp extends FieldAccessOp 1616 implements JavaExpression, JavaStatement { 1617 public static final String NAME = "field.store"; 1618 1619 public static FieldStoreOp create(ExternalizedOp def) { 1620 if (def.operands().size() > 2) { 1621 throw new IllegalArgumentException("Operation must accept one or two operands"); 1622 } 1623 1624 FieldRef fieldDescriptor = def.extractAttributeValue(ATTRIBUTE_FIELD_DESCRIPTOR, true, 1625 v -> switch (v) { 1626 case String s -> FieldRef.ofString(s); 1627 case FieldRef fd -> fd; 1628 default -> 1629 throw new UnsupportedOperationException("Unsupported field descriptor value:" + v); 1630 }); 1631 return new FieldStoreOp(def, fieldDescriptor); 1632 } 1633 1634 FieldStoreOp(ExternalizedOp opdef, FieldRef fieldDescriptor) { 1635 super(opdef, fieldDescriptor); 1636 } 1637 1638 FieldStoreOp(FieldStoreOp that, CopyContext cc) { 1639 super(that, cc); 1640 } 1641 1642 @Override 1643 public FieldStoreOp transform(CopyContext cc, OpTransformer ot) { 1644 return new FieldStoreOp(this, cc); 1645 } 1646 1647 // instance 1648 FieldStoreOp(FieldRef descriptor, Value receiver, Value v) { 1649 super(NAME, 1650 List.of(receiver, v), descriptor); 1651 } 1652 1653 // static 1654 FieldStoreOp(FieldRef descriptor, Value v) { 1655 super(NAME, 1656 List.of(v), descriptor); 1657 } 1658 1659 @Override 1660 public TypeElement resultType() { 1661 return JavaType.VOID; 1662 } 1663 } 1664 } 1665 1666 /** 1667 * The array length operation, that can model Java language field access expressions to the length field of an 1668 * array. 1669 */ 1670 @OpFactory.OpDeclaration(ArrayLengthOp.NAME) 1671 public static final class ArrayLengthOp extends CoreOp 1672 implements ReflectiveOp, JavaExpression { 1673 public static final String NAME = "array.length"; 1674 1675 public ArrayLengthOp(ExternalizedOp def) { 1676 super(def); 1677 } 1678 1679 ArrayLengthOp(ArrayLengthOp that, CopyContext cc) { 1680 super(that, cc); 1681 } 1682 1683 @Override 1684 public ArrayLengthOp transform(CopyContext cc, OpTransformer ot) { 1685 return new ArrayLengthOp(this, cc); 1686 } 1687 1688 ArrayLengthOp(Value array) { 1689 super(NAME, List.of(array)); 1690 } 1691 1692 @Override 1693 public TypeElement resultType() { 1694 return JavaType.INT; 1695 } 1696 } 1697 1698 /** 1699 * The array access operation, that can model Java language array access expressions. 1700 */ 1701 public sealed abstract static class ArrayAccessOp extends CoreOp 1702 implements AccessOp, ReflectiveOp { 1703 ArrayAccessOp(ExternalizedOp def) { 1704 super(def); 1705 1706 if (def.operands().size() != 2 && def.operands().size() != 3) { 1707 throw new IllegalArgumentException("Operation must have 2 or 3 operands"); 1708 } 1709 1710 // @@@ validate first operand is an array 1711 } 1712 1713 ArrayAccessOp(ArrayAccessOp that, CopyContext cc) { 1714 this(that, cc.getValues(that.operands())); 1715 } 1716 1717 ArrayAccessOp(ArrayAccessOp that, List<Value> operands) { 1718 super(that.opName(), operands); 1719 } 1720 1721 ArrayAccessOp(String name, 1722 Value array, Value index, Value v) { 1723 super(name, operands(array, index, v)); 1724 } 1725 1726 static List<Value> operands(Value array, Value index, Value v) { 1727 return v == null 1728 ? List.of(array, index) 1729 : List.of(array, index, v); 1730 } 1731 1732 static TypeElement resultType(Value array, Value v) { 1733 if (!(array.type() instanceof ArrayType arrayType)) { 1734 throw new IllegalArgumentException("Type is not an array type: " + array.type()); 1735 } 1736 1737 // @@@ restrict to indexes of int? 1738 TypeElement componentType = arrayType.componentType(); 1739 if (v == null) { 1740 return componentType; 1741 } else { 1742 return JavaType.VOID; 1743 } 1744 } 1745 1746 /** 1747 * The array load operation, that can model Java language array expressions combined with load access to the 1748 * components of an array. 1749 */ 1750 @OpFactory.OpDeclaration(ArrayLoadOp.NAME) 1751 public static final class ArrayLoadOp extends ArrayAccessOp 1752 implements Op.Pure, JavaExpression { 1753 public static final String NAME = "array.load"; 1754 1755 public ArrayLoadOp(ExternalizedOp def) { 1756 super(def); 1757 } 1758 1759 ArrayLoadOp(ArrayLoadOp that, CopyContext cc) { 1760 super(that, cc); 1761 } 1762 1763 @Override 1764 public ArrayLoadOp transform(CopyContext cc, OpTransformer ot) { 1765 return new ArrayLoadOp(this, cc); 1766 } 1767 1768 ArrayLoadOp(Value array, Value index) { 1769 super(NAME, array, index, null); 1770 } 1771 1772 @Override 1773 public TypeElement resultType() { 1774 Value array = operands().get(0); 1775 ArrayType t = (ArrayType) array.type(); 1776 return t.componentType(); 1777 } 1778 } 1779 1780 /** 1781 * The array store operation, that can model Java language array expressions combined with store access to the 1782 * components of an array. 1783 */ 1784 @OpFactory.OpDeclaration(ArrayStoreOp.NAME) 1785 public static final class ArrayStoreOp extends ArrayAccessOp 1786 implements JavaExpression, JavaStatement { 1787 public static final String NAME = "array.store"; 1788 1789 public ArrayStoreOp(ExternalizedOp def) { 1790 super(def); 1791 } 1792 1793 ArrayStoreOp(ArrayStoreOp that, CopyContext cc) { 1794 super(that, cc); 1795 } 1796 1797 @Override 1798 public ArrayStoreOp transform(CopyContext cc, OpTransformer ot) { 1799 return new ArrayStoreOp(this, cc); 1800 } 1801 1802 ArrayStoreOp(Value array, Value index, Value v) { 1803 super(NAME, array, index, v); 1804 } 1805 1806 @Override 1807 public TypeElement resultType() { 1808 return JavaType.VOID; 1809 } 1810 } 1811 } 1812 1813 /** 1814 * The instanceof operation, that can model Java language instanceof expressions when the instanceof keyword is a 1815 * type comparison operator. 1816 */ 1817 @OpFactory.OpDeclaration(InstanceOfOp.NAME) 1818 public static final class InstanceOfOp extends CoreOp 1819 implements Op.Pure, ReflectiveOp, JavaExpression { 1820 public static final String NAME = "instanceof"; 1821 public static final String ATTRIBUTE_TYPE_DESCRIPTOR = NAME + ".descriptor"; 1822 1823 final TypeElement typeDescriptor; 1824 1825 public static InstanceOfOp create(ExternalizedOp def) { 1826 if (def.operands().size() != 1) { 1827 throw new IllegalArgumentException("Operation must have one operand " + def.name()); 1828 } 1829 1830 TypeElement typeDescriptor = def.extractAttributeValue(ATTRIBUTE_TYPE_DESCRIPTOR, true, 1831 v -> switch (v) { 1832 case String s -> JavaType.ofString(s); 1833 case JavaType td -> td; 1834 default -> throw new UnsupportedOperationException("Unsupported type descriptor value:" + v); 1835 }); 1836 return new InstanceOfOp(def, typeDescriptor); 1837 } 1838 1839 InstanceOfOp(ExternalizedOp def, TypeElement typeDescriptor) { 1840 super(def); 1841 1842 this.typeDescriptor = typeDescriptor; 1843 } 1844 1845 InstanceOfOp(InstanceOfOp that, CopyContext cc) { 1846 super(that, cc); 1847 1848 this.typeDescriptor = that.typeDescriptor; 1849 } 1850 1851 @Override 1852 public InstanceOfOp transform(CopyContext cc, OpTransformer ot) { 1853 return new InstanceOfOp(this, cc); 1854 } 1855 1856 InstanceOfOp(TypeElement t, Value v) { 1857 super(NAME, 1858 List.of(v)); 1859 1860 this.typeDescriptor = t; 1861 } 1862 1863 @Override 1864 public Map<String, Object> attributes() { 1865 HashMap<String, Object> m = new HashMap<>(super.attributes()); 1866 m.put("", typeDescriptor); 1867 return Collections.unmodifiableMap(m); 1868 } 1869 1870 public TypeElement type() { 1871 return typeDescriptor; 1872 } 1873 1874 @Override 1875 public TypeElement resultType() { 1876 return JavaType.BOOLEAN; 1877 } 1878 } 1879 1880 /** 1881 * The cast operation, that can model Java language cast expressions for reference types. 1882 */ 1883 @OpFactory.OpDeclaration(CastOp.NAME) 1884 public static final class CastOp extends CoreOp 1885 implements Op.Pure, ReflectiveOp, JavaExpression { 1886 public static final String NAME = "cast"; 1887 public static final String ATTRIBUTE_TYPE_DESCRIPTOR = NAME + ".descriptor"; 1888 1889 final TypeElement resultType; 1890 final TypeElement typeDescriptor; 1891 1892 public static CastOp create(ExternalizedOp def) { 1893 if (def.operands().size() != 1) { 1894 throw new IllegalArgumentException("Operation must have one operand " + def.name()); 1895 } 1896 1897 TypeElement type = def.extractAttributeValue(ATTRIBUTE_TYPE_DESCRIPTOR, true, 1898 v -> switch (v) { 1899 case String s -> JavaType.ofString(s); 1900 case JavaType td -> td; 1901 default -> throw new UnsupportedOperationException("Unsupported type descriptor value:" + v); 1902 }); 1903 return new CastOp(def, type); 1904 } 1905 1906 CastOp(ExternalizedOp def, TypeElement typeDescriptor) { 1907 super(def); 1908 1909 this.resultType = def.resultType(); 1910 this.typeDescriptor = typeDescriptor; 1911 } 1912 1913 CastOp(CastOp that, CopyContext cc) { 1914 super(that, cc); 1915 1916 this.resultType = that.resultType; 1917 this.typeDescriptor = that.typeDescriptor; 1918 } 1919 1920 @Override 1921 public CastOp transform(CopyContext cc, OpTransformer ot) { 1922 return new CastOp(this, cc); 1923 } 1924 1925 CastOp(TypeElement resultType, TypeElement t, Value v) { 1926 super(NAME, List.of(v)); 1927 1928 this.resultType = resultType; 1929 this.typeDescriptor = t; 1930 } 1931 1932 @Override 1933 public Map<String, Object> attributes() { 1934 HashMap<String, Object> m = new HashMap<>(super.attributes()); 1935 m.put("", typeDescriptor); 1936 return Collections.unmodifiableMap(m); 1937 } 1938 1939 public TypeElement type() { 1940 return typeDescriptor; 1941 } 1942 1943 @Override 1944 public TypeElement resultType() { 1945 return resultType; 1946 } 1947 } 1948 1949 1950 /** 1951 * A runtime representation of a variable. 1952 * 1953 * @param <T> the type of the var's value. 1954 * @@@ Ideally should never be exposed 1955 * @@@ Move to interpreter? 1956 */ 1957 public interface Var<T> { 1958 /** 1959 * {@return the value of a var} 1960 */ 1961 T value(); 1962 1963 /** 1964 * Constructs an instance of a var. 1965 * 1966 * @param value the initial value of the var. 1967 * @param <T> the type of the var's value. 1968 * @return the var 1969 */ 1970 static <T> Var<T> of(T value) { 1971 return () -> value; 1972 } 1973 } 1974 1975 /** 1976 * The variable operation, that can model declarations of Java language local variables, method parameters, or 1977 * lambda parameters. 1978 */ 1979 @OpFactory.OpDeclaration(VarOp.NAME) 1980 public static final class VarOp extends CoreOp 1981 implements JavaStatement { 1982 public static final String NAME = "var"; 1983 public static final String ATTRIBUTE_NAME = NAME + ".name"; 1984 1985 final String varName; 1986 final TypeElement resultType; 1987 1988 public static VarOp create(ExternalizedOp def) { 1989 if (def.operands().size() != 1) { 1990 throw new IllegalStateException("Operation must have one operand"); 1991 } 1992 1993 String name = def.extractAttributeValue(ATTRIBUTE_NAME, true, 1994 v -> switch (v) { 1995 case String s -> s; 1996 default -> throw new UnsupportedOperationException("Unsupported var name value:" + v); 1997 }); 1998 return new VarOp(def, name); 1999 } 2000 2001 VarOp(ExternalizedOp def, String varName) { 2002 super(def); 2003 2004 this.varName = varName; 2005 this.resultType = def.resultType(); 2006 } 2007 2008 VarOp(VarOp that, CopyContext cc) { 2009 super(that, cc); 2010 2011 this.varName = that.varName; 2012 this.resultType = that.resultType; 2013 } 2014 2015 @Override 2016 public VarOp transform(CopyContext cc, OpTransformer ot) { 2017 return new VarOp(this, cc); 2018 } 2019 2020 VarOp(String varName, Value init) { 2021 this(varName, init.type(), init); 2022 } 2023 2024 VarOp(String varName, TypeElement type, Value init) { 2025 super(NAME, List.of(init)); 2026 2027 this.varName = varName; 2028 this.resultType = VarType.varType(type); 2029 } 2030 2031 @Override 2032 public Map<String, Object> attributes() { 2033 if (varName == null) { 2034 return super.attributes(); 2035 } 2036 2037 HashMap<String, Object> m = new HashMap<>(super.attributes()); 2038 m.put("", varName); 2039 return Collections.unmodifiableMap(m); 2040 } 2041 2042 public String varName() { 2043 return varName; 2044 } 2045 2046 public TypeElement varType() { 2047 return ((VarType) resultType).valueType(); 2048 } 2049 2050 @Override 2051 public TypeElement resultType() { 2052 return resultType; 2053 } 2054 } 2055 2056 /** 2057 * The var access operation, that can model access to Java language local variables, method parameters, or 2058 * lambda parameters. 2059 */ 2060 public sealed abstract static class VarAccessOp extends CoreOp 2061 implements AccessOp { 2062 VarAccessOp(ExternalizedOp opdef) { 2063 super(opdef); 2064 } 2065 2066 VarAccessOp(VarAccessOp that, CopyContext cc) { 2067 super(that, cc); 2068 } 2069 2070 VarAccessOp(String name, List<Value> operands) { 2071 super(name, operands); 2072 } 2073 2074 public VarOp varOp() { 2075 // @@@ At a high-level a Var value occur as a BlockArgument. 2076 // Lowering should remove such cases and the var definition should emerge 2077 // @@@ This method is used when transforming to pure SSA 2078 Result variable = (Result) operands().get(0); 2079 return (VarOp) variable.op(); 2080 } 2081 2082 static Value checkIsVarOp(Value varValue) { 2083 if (!(varValue.type() instanceof VarType)) { 2084 throw new IllegalArgumentException("Value's type is not a variable type: " + varValue); 2085 } 2086 return varValue; 2087 } 2088 2089 /** 2090 * The variable load operation, that models a reading variable. 2091 */ 2092 @OpFactory.OpDeclaration(VarLoadOp.NAME) 2093 public static final class VarLoadOp extends VarAccessOp 2094 implements JavaExpression { 2095 public static final String NAME = "var.load"; 2096 2097 public VarLoadOp(ExternalizedOp opdef) { 2098 super(opdef); 2099 2100 if (opdef.operands().size() != 1) { 2101 throw new IllegalArgumentException("Operation must have one operand"); 2102 } 2103 checkIsVarOp(opdef.operands().get(0)); 2104 } 2105 2106 VarLoadOp(VarLoadOp that, CopyContext cc) { 2107 super(that, cc); 2108 } 2109 2110 VarLoadOp(List<Value> varValue) { 2111 super(NAME, varValue); 2112 } 2113 2114 @Override 2115 public VarLoadOp transform(CopyContext cc, OpTransformer ot) { 2116 return new VarLoadOp(this, cc); 2117 } 2118 2119 // (Variable)VarType 2120 VarLoadOp(Value varValue) { 2121 super(NAME, List.of(varValue)); 2122 } 2123 2124 @Override 2125 public TypeElement resultType() { 2126 VarType vt = (VarType) operands().get(0).type(); 2127 return vt.valueType(); 2128 } 2129 } 2130 2131 /** 2132 * The variable store operation, that can model a variable assignment. 2133 */ 2134 @OpFactory.OpDeclaration(VarStoreOp.NAME) 2135 public static final class VarStoreOp extends VarAccessOp 2136 implements JavaExpression, JavaStatement { 2137 public static final String NAME = "var.store"; 2138 2139 public VarStoreOp(ExternalizedOp opdef) { 2140 super(opdef); 2141 2142 if (opdef.operands().size() != 2) { 2143 throw new IllegalArgumentException("Operation must have two operands"); 2144 } 2145 checkIsVarOp(opdef.operands().get(0)); 2146 } 2147 2148 VarStoreOp(VarStoreOp that, CopyContext cc) { 2149 super(that, cc); 2150 } 2151 2152 VarStoreOp(List<Value> values) { 2153 super(NAME, 2154 values); 2155 } 2156 2157 @Override 2158 public VarStoreOp transform(CopyContext cc, OpTransformer ot) { 2159 return new VarStoreOp(this, cc); 2160 } 2161 2162 // (Variable, VarType)void 2163 VarStoreOp(Value varValue, Value v) { 2164 super(NAME, 2165 List.of(varValue, v)); 2166 } 2167 2168 @Override 2169 public TypeElement resultType() { 2170 return JavaType.VOID; 2171 } 2172 } 2173 } 2174 2175 // Tuple operations, for modelling return with multiple values 2176 2177 /** 2178 * The tuple operation. A tuple contain a fixed set of values accessible by their component index. 2179 */ 2180 @OpFactory.OpDeclaration(TupleOp.NAME) 2181 public static final class TupleOp extends CoreOp { 2182 public static final String NAME = "tuple"; 2183 2184 public TupleOp(ExternalizedOp def) { 2185 super(def); 2186 } 2187 2188 TupleOp(TupleOp that, CopyContext cc) { 2189 this(cc.getValues(that.operands())); 2190 } 2191 2192 @Override 2193 public TupleOp transform(CopyContext cc, OpTransformer ot) { 2194 return new TupleOp(this, cc); 2195 } 2196 2197 TupleOp(List<? extends Value> componentValues) { 2198 super(NAME, componentValues); 2199 } 2200 2201 @Override 2202 public TypeElement resultType() { 2203 return TupleType.tupleTypeFromValues(operands()); 2204 } 2205 } 2206 2207 /** 2208 * The tuple component load operation, that access the component of a tuple at a given, constant, component index. 2209 */ 2210 @OpFactory.OpDeclaration(TupleLoadOp.NAME) 2211 public static final class TupleLoadOp extends CoreOp { 2212 public static final String NAME = "tuple.load"; 2213 public static final String ATTRIBUTE_INDEX = NAME + ".index"; 2214 2215 final int index; 2216 2217 public static TupleLoadOp create(ExternalizedOp def) { 2218 if (def.operands().size() != 1) { 2219 throw new IllegalStateException("Operation must have one operand"); 2220 } 2221 2222 int index = def.extractAttributeValue(ATTRIBUTE_INDEX, true, 2223 v -> switch (v) { 2224 case String s -> Integer.valueOf(s); 2225 case Integer i -> i; 2226 default -> throw new UnsupportedOperationException("Unsupported tuple index value:" + v); 2227 }); 2228 return new TupleLoadOp(def, index); 2229 } 2230 2231 TupleLoadOp(ExternalizedOp def, int index) { 2232 super(def); 2233 2234 // @@@ Validate tuple type and index 2235 this.index = index; 2236 } 2237 2238 TupleLoadOp(TupleLoadOp that, CopyContext cc) { 2239 this(that, cc.getValues(that.operands())); 2240 } 2241 2242 TupleLoadOp(TupleLoadOp that, List<Value> values) { 2243 super(NAME, values); 2244 2245 this.index = that.index; 2246 } 2247 2248 @Override 2249 public TupleLoadOp transform(CopyContext cc, OpTransformer ot) { 2250 return new TupleLoadOp(this, cc); 2251 } 2252 2253 TupleLoadOp(Value tupleValue, int index) { 2254 super(NAME, List.of(tupleValue)); 2255 2256 this.index = index; 2257 } 2258 2259 @Override 2260 public Map<String, Object> attributes() { 2261 HashMap<String, Object> m = new HashMap<>(super.attributes()); 2262 m.put("", index); 2263 return Collections.unmodifiableMap(m); 2264 } 2265 2266 public int index() { 2267 return index; 2268 } 2269 2270 @Override 2271 public TypeElement resultType() { 2272 Value tupleValue = operands().get(0); 2273 TupleType t = (TupleType) tupleValue.type(); 2274 return t.componentTypes().get(index); 2275 } 2276 } 2277 2278 /** 2279 * The tuple component set operation, that access the component of a tuple at a given, constant, component index. 2280 */ 2281 @OpFactory.OpDeclaration(TupleWithOp.NAME) 2282 public static final class TupleWithOp extends CoreOp { 2283 public static final String NAME = "tuple.with"; 2284 public static final String ATTRIBUTE_INDEX = NAME + ".index"; 2285 2286 final int index; 2287 2288 public static TupleWithOp create(ExternalizedOp def) { 2289 if (def.operands().size() != 2) { 2290 throw new IllegalStateException("Operation must have two operands"); 2291 } 2292 2293 int index = def.extractAttributeValue(ATTRIBUTE_INDEX, true, 2294 v -> switch (v) { 2295 case String s -> Integer.valueOf(s); 2296 case Integer i -> i; 2297 default -> throw new UnsupportedOperationException("Unsupported tuple index value:" + v); 2298 }); 2299 return new TupleWithOp(def, index); 2300 } 2301 2302 TupleWithOp(ExternalizedOp def, int index) { 2303 super(def); 2304 2305 // @@@ Validate tuple type and index 2306 this.index = index; 2307 } 2308 2309 TupleWithOp(TupleWithOp that, CopyContext cc) { 2310 this(that, cc.getValues(that.operands())); 2311 } 2312 2313 TupleWithOp(TupleWithOp that, List<Value> values) { 2314 super(NAME, values); 2315 2316 this.index = that.index; 2317 } 2318 2319 @Override 2320 public TupleWithOp transform(CopyContext cc, OpTransformer ot) { 2321 return new TupleWithOp(this, cc); 2322 } 2323 2324 TupleWithOp(Value tupleValue, int index, Value value) { 2325 super(NAME, List.of(tupleValue, value)); 2326 2327 // @@@ Validate tuple type and index 2328 this.index = index; 2329 } 2330 2331 @Override 2332 public Map<String, Object> attributes() { 2333 HashMap<String, Object> m = new HashMap<>(super.attributes()); 2334 m.put("", index); 2335 return Collections.unmodifiableMap(m); 2336 } 2337 2338 public int index() { 2339 return index; 2340 } 2341 2342 @Override 2343 public TypeElement resultType() { 2344 Value tupleValue = operands().get(0); 2345 TupleType tupleType = (TupleType) tupleValue.type(); 2346 Value value = operands().get(2); 2347 2348 List<TypeElement> tupleComponentTypes = new ArrayList<>(tupleType.componentTypes()); 2349 tupleComponentTypes.set(index, value.type()); 2350 return TupleType.tupleType(tupleComponentTypes); 2351 } 2352 } 2353 2354 // @@@ Sealed 2355 // Synthetic/hidden type that is the result type of an ExceptionRegionStart operation 2356 // and is an operand of an ExceptionRegionEnd operation 2357 2358 /** 2359 * A synthetic exception region type, that is the operation result-type of an exception region 2360 * start operation. 2361 */ 2362 // @@@: Create as new type element 2363 public interface ExceptionRegion { 2364 TypeElement EXCEPTION_REGION_TYPE = JavaType.type(ExceptionRegion.class); 2365 } 2366 2367 /** 2368 * The exception region start operation. 2369 */ 2370 @OpFactory.OpDeclaration(ExceptionRegionEnter.NAME) 2371 public static final class ExceptionRegionEnter extends CoreOp 2372 implements Op.BlockTerminating { 2373 public static final String NAME = "exception.region.enter"; 2374 2375 // First successor is the non-exceptional successor whose target indicates 2376 // the first block in the exception region. 2377 // One or more subsequent successors target the exception catching blocks 2378 // each of which have one block argument whose type is an exception type. 2379 final List<Block.Reference> s; 2380 2381 public ExceptionRegionEnter(ExternalizedOp def) { 2382 super(def); 2383 2384 if (def.successors().size() < 2) { 2385 throw new IllegalArgumentException("Operation must have two or more successors" + def.name()); 2386 } 2387 2388 this.s = List.copyOf(def.successors()); 2389 } 2390 2391 ExceptionRegionEnter(ExceptionRegionEnter that, CopyContext cc) { 2392 super(that, cc); 2393 2394 this.s = that.s.stream().map(cc::getSuccessorOrCreate).toList(); 2395 } 2396 2397 @Override 2398 public ExceptionRegionEnter transform(CopyContext cc, OpTransformer ot) { 2399 return new ExceptionRegionEnter(this, cc); 2400 } 2401 2402 ExceptionRegionEnter(List<Block.Reference> s) { 2403 super(NAME, List.of()); 2404 2405 if (s.size() < 2) { 2406 throw new IllegalArgumentException("Operation must have two or more successors" + opName()); 2407 } 2408 2409 this.s = List.copyOf(s); 2410 } 2411 2412 @Override 2413 public List<Block.Reference> successors() { 2414 return s; 2415 } 2416 2417 public Block.Reference start() { 2418 return s.get(0); 2419 } 2420 2421 public List<Block.Reference> catchBlocks() { 2422 return s.subList(1, s.size()); 2423 } 2424 2425 @Override 2426 public TypeElement resultType() { 2427 return ExceptionRegion.EXCEPTION_REGION_TYPE; 2428 } 2429 } 2430 2431 /** 2432 * The exception region end operation. 2433 */ 2434 @OpFactory.OpDeclaration(ExceptionRegionExit.NAME) 2435 public static final class ExceptionRegionExit extends CoreOp 2436 implements Op.BlockTerminating { 2437 public static final String NAME = "exception.region.exit"; 2438 2439 final Block.Reference end; 2440 2441 public ExceptionRegionExit(ExternalizedOp def) { 2442 super(def); 2443 2444 if (def.operands().size() != 1) { 2445 throw new IllegalArgumentException("Operation must have one operand" + def.name()); 2446 } 2447 2448 if (def.successors().size() != 1) { 2449 throw new IllegalArgumentException("Operation must have one successor" + def.name()); 2450 } 2451 2452 this.end = def.successors().get(0); 2453 } 2454 2455 ExceptionRegionExit(ExceptionRegionExit that, CopyContext cc) { 2456 super(that, cc); 2457 2458 this.end = cc.getSuccessorOrCreate(that.end); 2459 } 2460 2461 @Override 2462 public ExceptionRegionExit transform(CopyContext cc, OpTransformer ot) { 2463 return new ExceptionRegionExit(this, cc); 2464 } 2465 2466 ExceptionRegionExit(Value exceptionRegion, Block.Reference end) { 2467 super(NAME, checkValue(exceptionRegion)); 2468 2469 this.end = end; 2470 } 2471 2472 static List<Value> checkValue(Value er) { 2473 if (!(er instanceof Result or && or.op() instanceof ExceptionRegionEnter)) { 2474 throw new IllegalArgumentException( 2475 "Operand not the result of an exception.region.start operation: " + er); 2476 } 2477 2478 return List.of(er); 2479 } 2480 2481 @Override 2482 public List<Block.Reference> successors() { 2483 return List.of(end); 2484 } 2485 2486 public Block.Reference end() { 2487 return end; 2488 } 2489 2490 public ExceptionRegionEnter regionStart() { 2491 if (operands().get(0) instanceof Result or && 2492 or.op() instanceof ExceptionRegionEnter ers) { 2493 return ers; 2494 } 2495 throw new InternalError("Should not reach here"); 2496 } 2497 2498 @Override 2499 public TypeElement resultType() { 2500 return JavaType.VOID; 2501 } 2502 } 2503 2504 /** 2505 * The String Concatenation Operation 2506 */ 2507 2508 @OpFactory.OpDeclaration(ConcatOp.NAME) 2509 public static final class ConcatOp extends CoreOp 2510 implements Op.Pure, JavaExpression { 2511 public static final String NAME = "concat"; 2512 2513 public ConcatOp(ConcatOp that, CopyContext cc) { 2514 super(that, cc); 2515 } 2516 2517 public ConcatOp(ExternalizedOp def) { 2518 super(def); 2519 if (def.operands().size() != 2) { 2520 throw new IllegalArgumentException("Concatenation Operation must have two operands."); 2521 } 2522 } 2523 2524 public ConcatOp(Value lhs, Value rhs) { 2525 super(ConcatOp.NAME, List.of(lhs, rhs)); 2526 } 2527 2528 @Override 2529 public Op transform(CopyContext cc, OpTransformer ot) { 2530 return new ConcatOp(this, cc); 2531 } 2532 2533 @Override 2534 public TypeElement resultType() { 2535 return JavaType.J_L_STRING; 2536 } 2537 } 2538 2539 // 2540 // Arithmetic ops 2541 2542 /** 2543 * The arithmetic operation. 2544 */ 2545 public sealed static abstract class ArithmeticOperation extends CoreOp 2546 implements Op.Pure, JavaExpression { 2547 protected ArithmeticOperation(ExternalizedOp def) { 2548 super(def); 2549 2550 if (def.operands().isEmpty()) { 2551 throw new IllegalArgumentException("Operation must have one or more operands"); 2552 } 2553 } 2554 2555 protected ArithmeticOperation(ArithmeticOperation that, CopyContext cc) { 2556 super(that, cc); 2557 } 2558 2559 protected ArithmeticOperation(String name, List<Value> operands) { 2560 super(name, operands); 2561 } 2562 } 2563 2564 /** 2565 * The test operation. 2566 */ 2567 public sealed static abstract class TestOperation extends CoreOp 2568 implements Op.Pure, JavaExpression { 2569 protected TestOperation(ExternalizedOp def) { 2570 super(def); 2571 2572 if (def.operands().isEmpty()) { 2573 throw new IllegalArgumentException("Operation must have one or more operands"); 2574 } 2575 } 2576 2577 protected TestOperation(TestOperation that, CopyContext cc) { 2578 super(that, cc); 2579 } 2580 2581 protected TestOperation(String name, List<Value> operands) { 2582 super(name, operands); 2583 } 2584 } 2585 2586 /** 2587 * The binary arithmetic operation. 2588 */ 2589 public sealed static abstract class BinaryOp extends ArithmeticOperation { 2590 protected BinaryOp(ExternalizedOp def) { 2591 super(def); 2592 2593 if (def.operands().size() != 2) { 2594 throw new IllegalArgumentException("Number of operands must be 2: " + def.operands().size()); 2595 } 2596 } 2597 2598 protected BinaryOp(BinaryOp that, CopyContext cc) { 2599 super(that, cc); 2600 } 2601 2602 protected BinaryOp(String name, Value lhs, Value rhs) { 2603 super(name, List.of(lhs, rhs)); 2604 } 2605 2606 @Override 2607 public TypeElement resultType() { 2608 return operands().get(0).type(); 2609 } 2610 } 2611 2612 /** 2613 * The unary arithmetic operation. 2614 */ 2615 public sealed static abstract class UnaryOp extends ArithmeticOperation { 2616 protected UnaryOp(ExternalizedOp def) { 2617 super(def); 2618 2619 if (def.operands().size() != 1) { 2620 throw new IllegalArgumentException("Number of operands must be 1: " + def.operands().size()); 2621 } 2622 } 2623 2624 protected UnaryOp(UnaryOp that, CopyContext cc) { 2625 super(that, cc); 2626 } 2627 2628 protected UnaryOp(String name, Value v) { 2629 super(name, List.of(v)); 2630 } 2631 2632 @Override 2633 public TypeElement resultType() { 2634 return operands().get(0).type(); 2635 } 2636 } 2637 2638 /** 2639 * The binary test operation. 2640 */ 2641 public sealed static abstract class BinaryTestOp extends TestOperation { 2642 protected BinaryTestOp(ExternalizedOp def) { 2643 super(def); 2644 2645 if (def.operands().size() != 2) { 2646 throw new IllegalArgumentException("Number of operands must be 2: " + def.operands().size()); 2647 } 2648 } 2649 2650 protected BinaryTestOp(BinaryTestOp that, CopyContext cc) { 2651 super(that, cc); 2652 } 2653 2654 protected BinaryTestOp(String name, Value lhs, Value rhs) { 2655 super(name, List.of(lhs, rhs)); 2656 } 2657 2658 @Override 2659 public TypeElement resultType() { 2660 return JavaType.BOOLEAN; 2661 } 2662 } 2663 2664 /** 2665 * The add operation, that can model the Java language binary {@code +} operator for numeric types 2666 */ 2667 @OpFactory.OpDeclaration(AddOp.NAME) 2668 public static final class AddOp extends BinaryOp { 2669 public static final String NAME = "add"; 2670 2671 public AddOp(ExternalizedOp def) { 2672 super(def); 2673 } 2674 2675 AddOp(AddOp that, CopyContext cc) { 2676 super(that, cc); 2677 } 2678 2679 @Override 2680 public AddOp transform(CopyContext cc, OpTransformer ot) { 2681 return new AddOp(this, cc); 2682 } 2683 2684 AddOp(Value lhs, Value rhs) { 2685 super(NAME, lhs, rhs); 2686 } 2687 } 2688 2689 /** 2690 * The sub operation, that can model the Java language binary {@code -} operator for numeric types 2691 */ 2692 @OpFactory.OpDeclaration(SubOp.NAME) 2693 public static final class SubOp extends BinaryOp { 2694 public static final String NAME = "sub"; 2695 2696 public SubOp(ExternalizedOp opdef) { 2697 super(opdef); 2698 } 2699 2700 SubOp(SubOp that, CopyContext cc) { 2701 super(that, cc); 2702 } 2703 2704 @Override 2705 public SubOp transform(CopyContext cc, OpTransformer ot) { 2706 return new SubOp(this, cc); 2707 } 2708 2709 SubOp(Value lhs, Value rhs) { 2710 super(NAME, lhs, rhs); 2711 } 2712 } 2713 2714 /** 2715 * The mul operation, that can model the Java language binary {@code *} operator for numeric types 2716 */ 2717 @OpFactory.OpDeclaration(MulOp.NAME) 2718 public static final class MulOp extends BinaryOp { 2719 public static final String NAME = "mul"; 2720 2721 public MulOp(ExternalizedOp opdef) { 2722 super(opdef); 2723 } 2724 2725 MulOp(MulOp that, CopyContext cc) { 2726 super(that, cc); 2727 } 2728 2729 @Override 2730 public MulOp transform(CopyContext cc, OpTransformer ot) { 2731 return new MulOp(this, cc); 2732 } 2733 2734 MulOp(Value lhs, Value rhs) { 2735 super(NAME, lhs, rhs); 2736 } 2737 } 2738 2739 /** 2740 * The div operation, that can model the Java language binary {@code /} operator for numeric types 2741 */ 2742 @OpFactory.OpDeclaration(DivOp.NAME) 2743 public static final class DivOp extends BinaryOp { 2744 public static final String NAME = "div"; 2745 2746 public DivOp(ExternalizedOp opdef) { 2747 super(opdef); 2748 } 2749 2750 DivOp(DivOp that, CopyContext cc) { 2751 super(that, cc); 2752 } 2753 2754 @Override 2755 public DivOp transform(CopyContext cc, OpTransformer ot) { 2756 return new DivOp(this, cc); 2757 } 2758 2759 DivOp(Value lhs, Value rhs) { 2760 super(NAME, lhs, rhs); 2761 } 2762 } 2763 2764 /** 2765 * The mod operation, that can model the Java language binary {@code %} operator for numeric types 2766 */ 2767 @OpFactory.OpDeclaration(ModOp.NAME) 2768 public static final class ModOp extends BinaryOp { 2769 public static final String NAME = "mod"; 2770 2771 public ModOp(ExternalizedOp opdef) { 2772 super(opdef); 2773 } 2774 2775 ModOp(ModOp that, CopyContext cc) { 2776 super(that, cc); 2777 } 2778 2779 @Override 2780 public ModOp transform(CopyContext cc, OpTransformer ot) { 2781 return new ModOp(this, cc); 2782 } 2783 2784 ModOp(Value lhs, Value rhs) { 2785 super(NAME, lhs, rhs); 2786 } 2787 } 2788 2789 /** 2790 * The bitwise/logical or operation, that can model the Java language binary {@code |} operator for integral types 2791 * and booleans 2792 */ 2793 @OpFactory.OpDeclaration(OrOp.NAME) 2794 public static final class OrOp extends BinaryOp { 2795 public static final String NAME = "or"; 2796 2797 public OrOp(ExternalizedOp opdef) { 2798 super(opdef); 2799 } 2800 2801 OrOp(OrOp that, CopyContext cc) { 2802 super(that, cc); 2803 } 2804 2805 @Override 2806 public OrOp transform(CopyContext cc, OpTransformer ot) { 2807 return new OrOp(this, cc); 2808 } 2809 2810 OrOp(Value lhs, Value rhs) { 2811 super(NAME, lhs, rhs); 2812 } 2813 } 2814 2815 /** 2816 * The bitwise/logical and operation, that can model the Java language binary {@code &} operator for integral types 2817 * and booleans 2818 */ 2819 @OpFactory.OpDeclaration(AndOp.NAME) 2820 public static final class AndOp extends BinaryOp { 2821 public static final String NAME = "and"; 2822 2823 public AndOp(ExternalizedOp opdef) { 2824 super(opdef); 2825 } 2826 2827 AndOp(AndOp that, CopyContext cc) { 2828 super(that, cc); 2829 } 2830 2831 @Override 2832 public AndOp transform(CopyContext cc, OpTransformer ot) { 2833 return new AndOp(this, cc); 2834 } 2835 2836 AndOp(Value lhs, Value rhs) { 2837 super(NAME, lhs, rhs); 2838 } 2839 } 2840 2841 /** 2842 * The xor operation, that can model the Java language binary {@code ^} operator for integral types 2843 * and booleans 2844 */ 2845 @OpFactory.OpDeclaration(XorOp.NAME) 2846 public static final class XorOp extends BinaryOp { 2847 public static final String NAME = "xor"; 2848 2849 public XorOp(ExternalizedOp opdef) { 2850 super(opdef); 2851 } 2852 2853 XorOp(XorOp that, CopyContext cc) { 2854 super(that, cc); 2855 } 2856 2857 @Override 2858 public XorOp transform(CopyContext cc, OpTransformer ot) { 2859 return new XorOp(this, cc); 2860 } 2861 2862 XorOp(Value lhs, Value rhs) { 2863 super(NAME, lhs, rhs); 2864 } 2865 } 2866 2867 /** 2868 * The (logical) shift left operation, that can model the Java language binary {@code <<} operator for integral types 2869 */ 2870 @OpFactory.OpDeclaration(LshlOp.NAME) 2871 public static final class LshlOp extends BinaryOp { 2872 public static final String NAME = "lshl"; 2873 2874 public LshlOp(ExternalizedOp opdef) { 2875 super(opdef); 2876 } 2877 2878 LshlOp(LshlOp that, CopyContext cc) { 2879 super(that, cc); 2880 } 2881 2882 @Override 2883 public LshlOp transform(CopyContext cc, OpTransformer ot) { 2884 return new LshlOp(this, cc); 2885 } 2886 2887 LshlOp(Value lhs, Value rhs) { 2888 super(NAME, lhs, rhs); 2889 } 2890 } 2891 2892 /** 2893 * The (arithmetic) shift right operation, that can model the Java language binary {@code >>} operator for integral types 2894 */ 2895 @OpFactory.OpDeclaration(AshrOp.NAME) 2896 public static final class AshrOp extends CoreOp.BinaryOp { 2897 public static final String NAME = "ashr"; 2898 2899 public AshrOp(ExternalizedOp opdef) { 2900 super(opdef); 2901 } 2902 2903 AshrOp(AshrOp that, CopyContext cc) { 2904 super(that, cc); 2905 } 2906 2907 @Override 2908 public AshrOp transform(CopyContext cc, OpTransformer ot) { 2909 return new AshrOp(this, cc); 2910 } 2911 2912 AshrOp(Value lhs, Value rhs) { 2913 super(NAME, lhs, rhs); 2914 } 2915 } 2916 2917 /** 2918 * The unsigned (logical) shift right operation, that can model the Java language binary {@code >>>} operator for integral types 2919 */ 2920 @OpFactory.OpDeclaration(LshrOp.NAME) 2921 public static final class LshrOp extends CoreOp.BinaryOp { 2922 public static final String NAME = "lshr"; 2923 2924 public LshrOp(ExternalizedOp opdef) { 2925 super(opdef); 2926 } 2927 2928 LshrOp(LshrOp that, CopyContext cc) { 2929 super(that, cc); 2930 } 2931 2932 @Override 2933 public LshrOp transform(CopyContext cc, OpTransformer ot) { 2934 return new LshrOp(this, cc); 2935 } 2936 2937 LshrOp(Value lhs, Value rhs) { 2938 super(NAME, lhs, rhs); 2939 } 2940 } 2941 2942 /** 2943 * The neg operation, that can model the Java language unary {@code -} operator for numeric types 2944 */ 2945 @OpFactory.OpDeclaration(NegOp.NAME) 2946 public static final class NegOp extends UnaryOp { 2947 public static final String NAME = "neg"; 2948 2949 public NegOp(ExternalizedOp opdef) { 2950 super(opdef); 2951 } 2952 2953 NegOp(NegOp that, CopyContext cc) { 2954 super(that, cc); 2955 } 2956 2957 @Override 2958 public NegOp transform(CopyContext cc, OpTransformer ot) { 2959 return new NegOp(this, cc); 2960 } 2961 2962 NegOp(Value v) { 2963 super(NAME, v); 2964 } 2965 } 2966 2967 /** 2968 * The not operation, that can model the Java language unary {@code !} operator for boolean types 2969 */ 2970 @OpFactory.OpDeclaration(NotOp.NAME) 2971 public static final class NotOp extends UnaryOp { 2972 public static final String NAME = "not"; 2973 2974 public NotOp(ExternalizedOp opdef) { 2975 super(opdef); 2976 } 2977 2978 NotOp(NotOp that, CopyContext cc) { 2979 super(that, cc); 2980 } 2981 2982 @Override 2983 public NotOp transform(CopyContext cc, OpTransformer ot) { 2984 return new NotOp(this, cc); 2985 } 2986 2987 NotOp(Value v) { 2988 super(NAME, v); 2989 } 2990 } 2991 2992 /** 2993 * The equals operation, that can model the Java language equality {@code ==} operator for numeric, boolean 2994 * and reference types 2995 */ 2996 @OpFactory.OpDeclaration(EqOp.NAME) 2997 public static final class EqOp extends BinaryTestOp { 2998 public static final String NAME = "eq"; 2999 3000 public EqOp(ExternalizedOp opdef) { 3001 super(opdef); 3002 } 3003 3004 EqOp(EqOp that, CopyContext cc) { 3005 super(that, cc); 3006 } 3007 3008 @Override 3009 public EqOp transform(CopyContext cc, OpTransformer ot) { 3010 return new EqOp(this, cc); 3011 } 3012 3013 EqOp(Value lhs, Value rhs) { 3014 super(NAME, lhs, rhs); 3015 } 3016 } 3017 3018 /** 3019 * The not equals operation, that can model the Java language equality {@code !=} operator for numeric, boolean 3020 * and reference types 3021 */ 3022 @OpFactory.OpDeclaration(NeqOp.NAME) 3023 public static final class NeqOp extends BinaryTestOp { 3024 public static final String NAME = "neq"; 3025 3026 public NeqOp(ExternalizedOp opdef) { 3027 super(opdef); 3028 } 3029 3030 NeqOp(NeqOp that, CopyContext cc) { 3031 super(that, cc); 3032 } 3033 3034 @Override 3035 public NeqOp transform(CopyContext cc, OpTransformer ot) { 3036 return new NeqOp(this, cc); 3037 } 3038 3039 NeqOp(Value lhs, Value rhs) { 3040 super(NAME, lhs, rhs); 3041 } 3042 } 3043 3044 /** 3045 * The greater than operation, that can model the Java language relational {@code >} operator for numeric types 3046 */ 3047 @OpFactory.OpDeclaration(GtOp.NAME) 3048 public static final class GtOp extends BinaryTestOp { 3049 public static final String NAME = "gt"; 3050 3051 public GtOp(ExternalizedOp opdef) { 3052 super(opdef); 3053 } 3054 3055 GtOp(GtOp that, CopyContext cc) { 3056 super(that, cc); 3057 } 3058 3059 @Override 3060 public GtOp transform(CopyContext cc, OpTransformer ot) { 3061 return new GtOp(this, cc); 3062 } 3063 3064 GtOp(Value lhs, Value rhs) { 3065 super(NAME, lhs, rhs); 3066 } 3067 } 3068 3069 /** 3070 * The greater than or equal to operation, that can model the Java language relational {@code >=} operator for 3071 * numeric types 3072 */ 3073 @OpFactory.OpDeclaration(GeOp.NAME) 3074 public static final class GeOp extends BinaryTestOp { 3075 public static final String NAME = "ge"; 3076 3077 public GeOp(ExternalizedOp opdef) { 3078 super(opdef); 3079 } 3080 3081 GeOp(GeOp that, CopyContext cc) { 3082 super(that, cc); 3083 } 3084 3085 @Override 3086 public GeOp transform(CopyContext cc, OpTransformer ot) { 3087 return new GeOp(this, cc); 3088 } 3089 3090 GeOp(Value lhs, Value rhs) { 3091 super(NAME, lhs, rhs); 3092 } 3093 } 3094 3095 /** 3096 * The less than operation, that can model the Java language relational {@code <} operator for 3097 * numeric types 3098 */ 3099 @OpFactory.OpDeclaration(LtOp.NAME) 3100 public static final class LtOp extends BinaryTestOp { 3101 public static final String NAME = "lt"; 3102 3103 public LtOp(ExternalizedOp opdef) { 3104 super(opdef); 3105 } 3106 3107 LtOp(LtOp that, CopyContext cc) { 3108 super(that, cc); 3109 } 3110 3111 @Override 3112 public LtOp transform(CopyContext cc, OpTransformer ot) { 3113 return new LtOp(this, cc); 3114 } 3115 3116 LtOp(Value lhs, Value rhs) { 3117 super(NAME, lhs, rhs); 3118 } 3119 } 3120 3121 /** 3122 * The less than or equal to operation, that can model the Java language relational {@code <=} operator for 3123 * numeric types 3124 */ 3125 @OpFactory.OpDeclaration(LeOp.NAME) 3126 public static final class LeOp extends BinaryTestOp { 3127 public static final String NAME = "le"; 3128 3129 public LeOp(ExternalizedOp opdef) { 3130 super(opdef); 3131 } 3132 3133 LeOp(LeOp that, CopyContext cc) { 3134 super(that, cc); 3135 } 3136 3137 @Override 3138 public LeOp transform(CopyContext cc, OpTransformer ot) { 3139 return new LeOp(this, cc); 3140 } 3141 3142 LeOp(Value lhs, Value rhs) { 3143 super(NAME, lhs, rhs); 3144 } 3145 } 3146 3147 3148 /** 3149 * A factory for core operations. 3150 */ 3151 // @@@ Compute lazily 3152 public static final OpFactory FACTORY = OpFactory.OP_FACTORY.get(CoreOp.class); 3153 3154 /** 3155 * Creates a function operation builder 3156 * 3157 * @param funcName the function name 3158 * @param funcType the function type 3159 * @return the function operation builder 3160 */ 3161 public static FuncOp.Builder func(String funcName, FunctionType funcType) { 3162 return new FuncOp.Builder(null, funcName, funcType); 3163 } 3164 3165 /** 3166 * Creates a function operation 3167 * 3168 * @param funcName the function name 3169 * @param body the function body 3170 * @return the function operation 3171 */ 3172 public static FuncOp func(String funcName, Body.Builder body) { 3173 return new FuncOp(funcName, body); 3174 } 3175 3176 /** 3177 * Creates a function call operation 3178 * 3179 * @param funcName the name of the function operation 3180 * @param funcType the function type 3181 * @param args the function arguments 3182 * @return the function call operation 3183 */ 3184 public static FuncCallOp funcCall(String funcName, FunctionType funcType, Value... args) { 3185 return funcCall(funcName, funcType, List.of(args)); 3186 } 3187 3188 /** 3189 * Creates a function call operation 3190 * 3191 * @param funcName the name of the function operation 3192 * @param funcType the function type 3193 * @param args the function arguments 3194 * @return the function call operation 3195 */ 3196 public static FuncCallOp funcCall(String funcName, FunctionType funcType, List<Value> args) { 3197 return new FuncCallOp(funcName, funcType.returnType(), args); 3198 } 3199 3200 /** 3201 * Creates a function call operation 3202 * 3203 * @param func the target function 3204 * @param args the function arguments 3205 * @return the function call operation 3206 */ 3207 public static FuncCallOp funcCall(FuncOp func, Value... args) { 3208 return funcCall(func, List.of(args)); 3209 } 3210 3211 /** 3212 * Creates a function call operation 3213 * 3214 * @param func the target function 3215 * @param args the function argments 3216 * @return the function call operation 3217 */ 3218 public static FuncCallOp funcCall(FuncOp func, List<Value> args) { 3219 return new FuncCallOp(func.funcName(), func.invokableType().returnType(), args); 3220 } 3221 3222 /** 3223 * Creates a module operation. 3224 * 3225 * @param functions the functions of the module operation 3226 * @return the module operation 3227 */ 3228 public static ModuleOp module(FuncOp... functions) { 3229 return module(List.of(functions)); 3230 } 3231 3232 /** 3233 * Creates a module operation. 3234 * 3235 * @param functions the functions of the module operation 3236 * @return the module operation 3237 */ 3238 public static ModuleOp module(List<FuncOp> functions) { 3239 return new ModuleOp(List.copyOf(functions)); 3240 } 3241 3242 /** 3243 * Creates a quoted operation. 3244 * 3245 * @param ancestorBody the ancestor of the body of the quoted operation 3246 * @param opFunc a function that accepts the body of the quoted operation and returns the operation to be quoted 3247 * @return the quoted operation 3248 */ 3249 public static QuotedOp quoted(Body.Builder ancestorBody, 3250 Function<Block.Builder, Op> opFunc) { 3251 Body.Builder body = Body.Builder.of(ancestorBody, FunctionType.VOID); 3252 Block.Builder block = body.entryBlock(); 3253 block.op(_yield( 3254 block.op(opFunc.apply(block)))); 3255 return new QuotedOp(body); 3256 } 3257 3258 /** 3259 * Creates a quoted operation. 3260 * 3261 * @param body quoted operation body 3262 * @return the quoted operation 3263 */ 3264 public static QuotedOp quoted(Body.Builder body) { 3265 return new QuotedOp(body); 3266 } 3267 3268 /** 3269 * Creates a lambda operation. 3270 * 3271 * @param ancestorBody the ancestor of the body of the lambda operation 3272 * @param funcType the lambda operation's function type 3273 * @param functionalInterface the lambda operation's functional interface type 3274 * @return the lambda operation 3275 */ 3276 public static LambdaOp.Builder lambda(Body.Builder ancestorBody, 3277 FunctionType funcType, TypeElement functionalInterface) { 3278 return new LambdaOp.Builder(ancestorBody, funcType, functionalInterface); 3279 } 3280 3281 /** 3282 * Creates a lambda operation. 3283 * 3284 * @param functionalInterface the lambda operation's functional interface type 3285 * @param body the body of the lambda operation 3286 * @return the lambda operation 3287 */ 3288 public static LambdaOp lambda(TypeElement functionalInterface, Body.Builder body) { 3289 return new LambdaOp(functionalInterface, body); 3290 } 3291 3292 /** 3293 * Creates a closure operation. 3294 * 3295 * @param ancestorBody the ancestor of the body of the closure operation 3296 * @param funcType the closure operation's function type 3297 * @return the closure operation 3298 */ 3299 public static ClosureOp.Builder closure(Body.Builder ancestorBody, 3300 FunctionType funcType) { 3301 return new ClosureOp.Builder(ancestorBody, funcType); 3302 } 3303 3304 /** 3305 * Creates a closure operation. 3306 * 3307 * @param body the body of the closure operation 3308 * @return the closure operation 3309 */ 3310 public static ClosureOp closure(Body.Builder body) { 3311 return new ClosureOp(body); 3312 } 3313 3314 /** 3315 * Creates a closure call operation. 3316 * 3317 * @param args the closure arguments. The first argument is the closure operation to be called 3318 * @return the closure call operation 3319 */ 3320 // @@@: Is this the right signature? 3321 public static ClosureCallOp closureCall(Value... args) { 3322 return closureCall(List.of(args)); 3323 } 3324 3325 /** 3326 * Creates a closure call operation. 3327 * 3328 * @param args the closure arguments. The first argument is the closure operation to be called 3329 * @return the closure call operation 3330 */ 3331 // @@@: Is this the right signature? 3332 public static ClosureCallOp closureCall(List<Value> args) { 3333 return new ClosureCallOp(args); 3334 } 3335 3336 /** 3337 * Creates an exception region enter operation 3338 * 3339 * @param start the exception region block 3340 * @param catchers the blocks handling exceptions thrown by the region block 3341 * @return the exception region enter operation 3342 */ 3343 public static ExceptionRegionEnter exceptionRegionEnter(Block.Reference start, Block.Reference... catchers) { 3344 return exceptionRegionEnter(start, List.of(catchers)); 3345 } 3346 3347 /** 3348 * Creates an exception region enter operation 3349 * 3350 * @param start the exception region block 3351 * @param catchers the blocks handling exceptions thrown by the region block 3352 * @return the exception region enter operation 3353 */ 3354 public static ExceptionRegionEnter exceptionRegionEnter(Block.Reference start, List<Block.Reference> catchers) { 3355 List<Block.Reference> s = new ArrayList<>(); 3356 s.add(start); 3357 s.addAll(catchers); 3358 return new ExceptionRegionEnter(s); 3359 } 3360 3361 /** 3362 * Creates an exception region exit operation 3363 * 3364 * @param exceptionRegion the exception region to be exited 3365 * @param end the block to which control is transferred after the exception region is exited 3366 * @return the exception region exit operation 3367 */ 3368 public static ExceptionRegionExit exceptionRegionExit(Value exceptionRegion, Block.Reference end) { 3369 return new ExceptionRegionExit(exceptionRegion, end); 3370 } 3371 3372 /** 3373 * Creates a return operation. 3374 * 3375 * @return the return operation 3376 */ 3377 public static ReturnOp _return() { 3378 return new ReturnOp(); 3379 } 3380 3381 /** 3382 * Creates a return operation. 3383 * 3384 * @param returnValue the return value 3385 * @return the return operation 3386 */ 3387 public static ReturnOp _return(Value returnValue) { 3388 return new ReturnOp(returnValue); 3389 } 3390 3391 /** 3392 * Creates a throw operation. 3393 * 3394 * @param exceptionValue the thrown value 3395 * @return the throw operation 3396 */ 3397 public static ThrowOp _throw(Value exceptionValue) { 3398 return new ThrowOp(exceptionValue); 3399 } 3400 3401 /** 3402 * Creates an unreachable operation. 3403 * 3404 * @return the unreachable operation 3405 */ 3406 public static UnreachableOp unreachable() { 3407 return new UnreachableOp(); 3408 } 3409 3410 /** 3411 * Creates a yield operation. 3412 * 3413 * @return the yield operation 3414 */ 3415 public static YieldOp _yield() { 3416 return new YieldOp(); 3417 } 3418 3419 /** 3420 * Creates a yield operation. 3421 * 3422 * @param yieldValue the yielded value 3423 * @return the yield operation 3424 */ 3425 public static YieldOp _yield(Value yieldValue) { 3426 return new YieldOp(List.of(yieldValue)); 3427 } 3428 3429 /** 3430 * Creates an assert operation. 3431 * 3432 * @param bodies the nested bodies 3433 * @return the assert operation 3434 */ 3435 public static AssertOp _assert(List<Body.Builder> bodies) { 3436 return new AssertOp(bodies); 3437 } 3438 3439 /** 3440 * Creates an unconditional break operation. 3441 * 3442 * @param target the jump target 3443 * @return the unconditional break operation 3444 */ 3445 public static BranchOp branch(Block.Reference target) { 3446 return new BranchOp(target); 3447 } 3448 3449 /** 3450 * Creates a conditional break operation. 3451 * 3452 * @param condValue the test value of the conditional break operation 3453 * @param trueTarget the jump target when the test value evaluates to true 3454 * @param falseTarget the jump target when the test value evaluates to false 3455 * @return the conditional break operation 3456 */ 3457 public static ConditionalBranchOp conditionalBranch(Value condValue, 3458 Block.Reference trueTarget, Block.Reference falseTarget) { 3459 return new ConditionalBranchOp(condValue, trueTarget, falseTarget); 3460 } 3461 3462 /** 3463 * Creates a constant operation. 3464 * 3465 * @param type the constant type 3466 * @param value the constant value 3467 * @return the constant operation 3468 */ 3469 public static ConstantOp constant(TypeElement type, Object value) { 3470 return new ConstantOp(type, value); 3471 } 3472 3473 /** 3474 * Creates an invoke operation. 3475 * 3476 * @param invokeDescriptor the invocation descriptor 3477 * @param args the invoke parameters 3478 * @return the invoke operation 3479 */ 3480 public static InvokeOp invoke(MethodRef invokeDescriptor, Value... args) { 3481 return new InvokeOp(invokeDescriptor, List.of(args)); 3482 } 3483 3484 /** 3485 * Creates an invoke operation. 3486 * 3487 * @param invokeDescriptor the invocation descriptor 3488 * @param args the invoke parameters 3489 * @return the invoke operation 3490 */ 3491 public static InvokeOp invoke(MethodRef invokeDescriptor, List<Value> args) { 3492 return new InvokeOp(invokeDescriptor, args); 3493 } 3494 3495 /** 3496 * Creates an invoke operation. 3497 * 3498 * @param returnType the invocation return type 3499 * @param invokeDescriptor the invocation descriptor 3500 * @param args the invoke parameters 3501 * @return the invoke operation 3502 */ 3503 public static InvokeOp invoke(TypeElement returnType, MethodRef invokeDescriptor, Value... args) { 3504 return new InvokeOp(returnType, invokeDescriptor, List.of(args)); 3505 } 3506 3507 /** 3508 * Creates an invoke operation. 3509 * 3510 * @param returnType the invocation return type 3511 * @param invokeDescriptor the invocation descriptor 3512 * @param args the invoke parameters 3513 * @return the invoke operation 3514 */ 3515 public static InvokeOp invoke(TypeElement returnType, MethodRef invokeDescriptor, List<Value> args) { 3516 return new InvokeOp(returnType, invokeDescriptor, args); 3517 } 3518 3519 /** 3520 * Creates a conversion operation. 3521 * 3522 * @param to the conversion target type 3523 * @param from the value to be converted 3524 * @return the conversion operation 3525 */ 3526 public static ConvOp conv(TypeElement to, Value from) { 3527 return new ConvOp(to, from); 3528 } 3529 3530 /** 3531 * Creates an instance creation operation. 3532 * 3533 * @param constructorType the constructor type 3534 * @param args the constructor arguments 3535 * @return the instance creation operation 3536 */ 3537 public static NewOp _new(FunctionType constructorType, Value... args) { 3538 return _new(constructorType, List.of(args)); 3539 } 3540 3541 /** 3542 * Creates an instance creation operation. 3543 * 3544 * @param constructorType the constructor type 3545 * @param args the constructor arguments 3546 * @return the instance creation operation 3547 */ 3548 public static NewOp _new(FunctionType constructorType, List<Value> args) { 3549 return new NewOp(constructorType, args); 3550 } 3551 3552 /** 3553 * Creates an instance creation operation. 3554 * 3555 * @param returnType the instance type 3556 * @param constructorType the constructor type 3557 * @param args the constructor arguments 3558 * @return the instance creation operation 3559 */ 3560 public static NewOp _new(TypeElement returnType, FunctionType constructorType, 3561 Value... args) { 3562 return _new(returnType, constructorType, List.of(args)); 3563 } 3564 3565 /** 3566 * Creates an instance creation operation. 3567 * 3568 * @param returnType the instance type 3569 * @param constructorType the constructor type 3570 * @param args the constructor arguments 3571 * @return the instance creation operation 3572 */ 3573 public static NewOp _new(TypeElement returnType, FunctionType constructorType, 3574 List<Value> args) { 3575 return new NewOp(returnType, constructorType, args); 3576 } 3577 3578 /** 3579 * Creates an array creation operation. 3580 * 3581 * @param arrayType the array type 3582 * @param length the array size 3583 * @return the array creation operation 3584 */ 3585 public static NewOp newArray(TypeElement arrayType, Value length) { 3586 return _new(FunctionType.functionType(arrayType, JavaType.INT), length); 3587 } 3588 3589 // @@@ Add field load/store overload with explicit fieldType 3590 3591 /** 3592 * Creates a field load operation to a non-static field. 3593 * 3594 * @param descriptor the field descriptor 3595 * @param receiver the receiver value 3596 * @return the field load operation 3597 */ 3598 public static FieldAccessOp.FieldLoadOp fieldLoad(FieldRef descriptor, Value receiver) { 3599 return new FieldAccessOp.FieldLoadOp(descriptor.type(), descriptor, receiver); 3600 } 3601 3602 /** 3603 * Creates a field load operation to a non-static field. 3604 * 3605 * @param resultType the result type of the operation 3606 * @param descriptor the field descriptor 3607 * @param receiver the receiver value 3608 * @return the field load operation 3609 */ 3610 public static FieldAccessOp.FieldLoadOp fieldLoad(TypeElement resultType, FieldRef descriptor, Value receiver) { 3611 return new FieldAccessOp.FieldLoadOp(resultType, descriptor, receiver); 3612 } 3613 3614 /** 3615 * Creates a field load operation to a static field. 3616 * 3617 * @param descriptor the field descriptor 3618 * @return the field load operation 3619 */ 3620 public static FieldAccessOp.FieldLoadOp fieldLoad(FieldRef descriptor) { 3621 return new FieldAccessOp.FieldLoadOp(descriptor.type(), descriptor); 3622 } 3623 3624 /** 3625 * Creates a field load operation to a static field. 3626 * 3627 * @param resultType the result type of the operation 3628 * @param descriptor the field descriptor 3629 * @return the field load operation 3630 */ 3631 public static FieldAccessOp.FieldLoadOp fieldLoad(TypeElement resultType, FieldRef descriptor) { 3632 return new FieldAccessOp.FieldLoadOp(resultType, descriptor); 3633 } 3634 3635 /** 3636 * Creates a field store operation to a non-static field. 3637 * 3638 * @param descriptor the field descriptor 3639 * @param receiver the receiver value 3640 * @param v the value to store 3641 * @return the field store operation 3642 */ 3643 public static FieldAccessOp.FieldStoreOp fieldStore(FieldRef descriptor, Value receiver, Value v) { 3644 return new FieldAccessOp.FieldStoreOp(descriptor, receiver, v); 3645 } 3646 3647 /** 3648 * Creates a field load operation to a static field. 3649 * 3650 * @param descriptor the field descriptor 3651 * @param v the value to store 3652 * @return the field store operation 3653 */ 3654 public static FieldAccessOp.FieldStoreOp fieldStore(FieldRef descriptor, Value v) { 3655 return new FieldAccessOp.FieldStoreOp(descriptor, v); 3656 } 3657 3658 /** 3659 * Creates an array length operation. 3660 * 3661 * @param array the array value 3662 * @return the array length operation 3663 */ 3664 public static ArrayLengthOp arrayLength(Value array) { 3665 return new ArrayLengthOp(array); 3666 } 3667 3668 /** 3669 * Creates an array load operation. 3670 * 3671 * @param array the array value 3672 * @param index the index value 3673 * @return the array load operation 3674 */ 3675 public static ArrayAccessOp.ArrayLoadOp arrayLoadOp(Value array, Value index) { 3676 return new ArrayAccessOp.ArrayLoadOp(array, index); 3677 } 3678 3679 /** 3680 * Creates an array store operation. 3681 * 3682 * @param array the array value 3683 * @param index the index value 3684 * @param v the value to store 3685 * @return the array store operation 3686 */ 3687 public static ArrayAccessOp.ArrayStoreOp arrayStoreOp(Value array, Value index, Value v) { 3688 return new ArrayAccessOp.ArrayStoreOp(array, index, v); 3689 } 3690 3691 /** 3692 * Creates an instanceof operation. 3693 * 3694 * @param t the type to test against 3695 * @param v the value to test 3696 * @return the instanceof operation 3697 */ 3698 public static InstanceOfOp instanceOf(TypeElement t, Value v) { 3699 return new InstanceOfOp(t, v); 3700 } 3701 3702 /** 3703 * Creates a cast operation. 3704 * 3705 * @param resultType the result type of the operation 3706 * @param v the value to cast 3707 * @return the cast operation 3708 */ 3709 public static CastOp cast(TypeElement resultType, Value v) { 3710 return new CastOp(resultType, resultType, v); 3711 } 3712 3713 /** 3714 * Creates a cast operation. 3715 * 3716 * @param resultType the result type of the operation 3717 * @param t the type to cast to 3718 * @param v the value to cast 3719 * @return the cast operation 3720 */ 3721 public static CastOp cast(TypeElement resultType, JavaType t, Value v) { 3722 return new CastOp(resultType, t, v); 3723 } 3724 3725 /** 3726 * Creates a var operation. 3727 * 3728 * @param init the initial value of the var 3729 * @return the var operation 3730 */ 3731 public static VarOp var(Value init) { 3732 return var(null, init); 3733 } 3734 3735 /** 3736 * Creates a var operation. 3737 * 3738 * @param name the name of the var 3739 * @param init the initial value of the var 3740 * @return the var operation 3741 */ 3742 public static VarOp var(String name, Value init) { 3743 return new VarOp(name, init); 3744 } 3745 3746 /** 3747 * Creates a var operation. 3748 * 3749 * @param name the name of the var 3750 * @param type the type of the var's value 3751 * @param init the initial value of the var 3752 * @return the var operation 3753 */ 3754 public static VarOp var(String name, TypeElement type, Value init) { 3755 return new VarOp(name, type, init); 3756 } 3757 3758 /** 3759 * Creates a var load operation. 3760 * 3761 * @param varValue the var value 3762 * @return the var load operation 3763 */ 3764 public static VarAccessOp.VarLoadOp varLoad(Value varValue) { 3765 return new VarAccessOp.VarLoadOp(varValue); 3766 } 3767 3768 /** 3769 * Creates a var store operation. 3770 * 3771 * @param varValue the var value 3772 * @param v the value to store in the var 3773 * @return the var store operation 3774 */ 3775 public static VarAccessOp.VarStoreOp varStore(Value varValue, Value v) { 3776 return new VarAccessOp.VarStoreOp(varValue, v); 3777 } 3778 3779 /** 3780 * Creates a tuple operation. 3781 * 3782 * @param componentValues the values of tuple (in order) 3783 * @return the tuple operation 3784 */ 3785 public static TupleOp tuple(Value... componentValues) { 3786 return tuple(List.of(componentValues)); 3787 } 3788 3789 /** 3790 * Creates a tuple operation. 3791 * 3792 * @param componentValues the values of tuple (in order) 3793 * @return the tuple operation 3794 */ 3795 public static TupleOp tuple(List<? extends Value> componentValues) { 3796 return new TupleOp(componentValues); 3797 } 3798 3799 /** 3800 * Creates a tuple load operation. 3801 * 3802 * @param tuple the tuple value 3803 * @param index the component index value 3804 * @return the tuple load operation 3805 */ 3806 public static TupleLoadOp tupleLoad(Value tuple, int index) { 3807 return new TupleLoadOp(tuple, index); 3808 } 3809 3810 /** 3811 * Creates a tuple with operation. 3812 * 3813 * @param tuple the tuple value 3814 * @param index the component index value 3815 * @param value the component value 3816 * @return the tuple with operation 3817 */ 3818 public static TupleWithOp tupleWith(Value tuple, int index, Value value) { 3819 return new TupleWithOp(tuple, index, value); 3820 } 3821 3822 // 3823 // Arithmetic ops 3824 3825 /** 3826 * Creates an add operation. 3827 * 3828 * @param lhs the first operand 3829 * @param rhs the second operand 3830 * @return the add operation 3831 */ 3832 public static BinaryOp add(Value lhs, Value rhs) { 3833 return new AddOp(lhs, rhs); 3834 } 3835 3836 /** 3837 * Creates a sub operation. 3838 * 3839 * @param lhs the first operand 3840 * @param rhs the second operand 3841 * @return the sub operation 3842 */ 3843 public static BinaryOp sub(Value lhs, Value rhs) { 3844 return new SubOp(lhs, rhs); 3845 } 3846 3847 /** 3848 * Creates a mul operation. 3849 * 3850 * @param lhs the first operand 3851 * @param rhs the second operand 3852 * @return the mul operation 3853 */ 3854 public static BinaryOp mul(Value lhs, Value rhs) { 3855 return new MulOp(lhs, rhs); 3856 } 3857 3858 /** 3859 * Creates a div operation. 3860 * 3861 * @param lhs the first operand 3862 * @param rhs the second operand 3863 * @return the div operation 3864 */ 3865 public static BinaryOp div(Value lhs, Value rhs) { 3866 return new DivOp(lhs, rhs); 3867 } 3868 3869 /** 3870 * Creates a mod operation. 3871 * 3872 * @param lhs the first operand 3873 * @param rhs the second operand 3874 * @return the mod operation 3875 */ 3876 public static BinaryOp mod(Value lhs, Value rhs) { 3877 return new ModOp(lhs, rhs); 3878 } 3879 3880 /** 3881 * Creates a bitwise/logical or operation. 3882 * 3883 * @param lhs the first operand 3884 * @param rhs the second operand 3885 * @return the or operation 3886 */ 3887 public static BinaryOp or(Value lhs, Value rhs) { 3888 return new OrOp(lhs, rhs); 3889 } 3890 3891 /** 3892 * Creates a bitwise/logical and operation. 3893 * 3894 * @param lhs the first operand 3895 * @param rhs the second operand 3896 * @return the and operation 3897 */ 3898 public static BinaryOp and(Value lhs, Value rhs) { 3899 return new AndOp(lhs, rhs); 3900 } 3901 3902 /** 3903 * Creates a bitwise/logical xor operation. 3904 * 3905 * @param lhs the first operand 3906 * @param rhs the second operand 3907 * @return the xor operation 3908 */ 3909 public static BinaryOp xor(Value lhs, Value rhs) { 3910 return new XorOp(lhs, rhs); 3911 } 3912 3913 /** 3914 * Creates a left shift operation. 3915 * 3916 * @param lhs the first operand 3917 * @param rhs the second operand 3918 * @return the xor operation 3919 */ 3920 public static BinaryOp lshl(Value lhs, Value rhs) { 3921 return new LshlOp(lhs, rhs); 3922 } 3923 3924 /** 3925 * Creates a right shift operation. 3926 * 3927 * @param lhs the first operand 3928 * @param rhs the second operand 3929 * @return the xor operation 3930 */ 3931 public static BinaryOp ashr(Value lhs, Value rhs) { 3932 return new AshrOp(lhs, rhs); 3933 } 3934 3935 /** 3936 * Creates an unsigned right shift operation. 3937 * 3938 * @param lhs the first operand 3939 * @param rhs the second operand 3940 * @return the xor operation 3941 */ 3942 public static BinaryOp lshr(Value lhs, Value rhs) { 3943 return new LshrOp(lhs, rhs); 3944 } 3945 3946 /** 3947 * Creates a neg operation. 3948 * 3949 * @param v the operand 3950 * @return the neg operation 3951 */ 3952 public static UnaryOp neg(Value v) { 3953 return new NegOp(v); 3954 } 3955 3956 /** 3957 * Creates a not operation. 3958 * 3959 * @param v the operand 3960 * @return the not operation 3961 */ 3962 public static UnaryOp not(Value v) { 3963 return new NotOp(v); 3964 } 3965 3966 3967 /** 3968 * Creates an equals comparison operation. 3969 * 3970 * @param lhs the first operand 3971 * @param rhs the second operand 3972 * @return the equals comparison operation 3973 */ 3974 public static BinaryTestOp eq(Value lhs, Value rhs) { 3975 return new EqOp(lhs, rhs); 3976 } 3977 3978 /** 3979 * Creates a not equals comparison operation. 3980 * 3981 * @param lhs the first operand 3982 * @param rhs the second operand 3983 * @return the not equals comparison operation 3984 */ 3985 public static BinaryTestOp neq(Value lhs, Value rhs) { 3986 return new NeqOp(lhs, rhs); 3987 } 3988 3989 /** 3990 * Creates a greater than comparison operation. 3991 * 3992 * @param lhs the first operand 3993 * @param rhs the second operand 3994 * @return the greater than comparison operation 3995 */ 3996 public static BinaryTestOp gt(Value lhs, Value rhs) { 3997 return new GtOp(lhs, rhs); 3998 } 3999 4000 /** 4001 * Creates a greater than or equals to comparison operation. 4002 * 4003 * @param lhs the first operand 4004 * @param rhs the second operand 4005 * @return the greater than or equals to comparison operation 4006 */ 4007 public static BinaryTestOp ge(Value lhs, Value rhs) { 4008 return new GeOp(lhs, rhs); 4009 } 4010 4011 /** 4012 * Creates a less than comparison operation. 4013 * 4014 * @param lhs the first operand 4015 * @param rhs the second operand 4016 * @return the less than comparison operation 4017 */ 4018 public static BinaryTestOp lt(Value lhs, Value rhs) { 4019 return new LtOp(lhs, rhs); 4020 } 4021 4022 /** 4023 * Creates a less than or equals to comparison operation. 4024 * 4025 * @param lhs the first operand 4026 * @param rhs the second operand 4027 * @return the less than or equals to comparison operation 4028 */ 4029 public static BinaryTestOp le(Value lhs, Value rhs) { 4030 return new LeOp(lhs, rhs); 4031 } 4032 4033 /** 4034 * Creates a string concatenation operation. 4035 * 4036 * @param lhs the first operand 4037 * @param rhs the second operand 4038 * @return the string concatenation operation 4039 */ 4040 public static ConcatOp concat(Value lhs, Value rhs) { 4041 return new ConcatOp(lhs, rhs); 4042 } 4043 }