1 34 package org.codehaus.groovy.classgen; 35 36 import groovy.lang.Closure; 37 import groovy.lang.GString; 38 import groovy.lang.GroovyRuntimeException; 39 import groovy.lang.MissingClassException; 40 import groovy.lang.Reference; 41 42 import java.math.BigDecimal ; 43 import java.math.BigInteger ; 44 import java.security.AccessControlException ; 45 import java.util.ArrayList ; 46 import java.util.HashMap ; 47 import java.util.HashSet ; 48 import java.util.Iterator ; 49 import java.util.LinkedList ; 50 import java.util.List ; 51 import java.util.Map ; 52 import java.util.Set ; 53 import java.util.logging.Logger ; 54 55 import org.codehaus.groovy.ast.ASTNode; 56 import org.codehaus.groovy.ast.ClassNode; 57 import org.codehaus.groovy.ast.CodeVisitorSupport; 58 import org.codehaus.groovy.ast.CompileUnit; 59 import org.codehaus.groovy.ast.ConstructorNode; 60 import org.codehaus.groovy.ast.FieldNode; 61 import org.codehaus.groovy.ast.GroovyClassVisitor; 62 import org.codehaus.groovy.ast.GroovyCodeVisitor; 63 import org.codehaus.groovy.ast.InnerClassNode; 64 import org.codehaus.groovy.ast.MethodNode; 65 import org.codehaus.groovy.ast.Parameter; 66 import org.codehaus.groovy.ast.PropertyNode; 67 import org.codehaus.groovy.ast.Type; 68 import org.codehaus.groovy.ast.VariableScope; 69 import org.codehaus.groovy.ast.expr.ArgumentListExpression; 70 import org.codehaus.groovy.ast.expr.ArrayExpression; 71 import org.codehaus.groovy.ast.expr.BinaryExpression; 72 import org.codehaus.groovy.ast.expr.BooleanExpression; 73 import org.codehaus.groovy.ast.expr.CastExpression; 74 import org.codehaus.groovy.ast.expr.ClassExpression; 75 import org.codehaus.groovy.ast.expr.ClosureExpression; 76 import org.codehaus.groovy.ast.expr.ConstantExpression; 77 import org.codehaus.groovy.ast.expr.ConstructorCallExpression; 78 import org.codehaus.groovy.ast.expr.Expression; 79 import org.codehaus.groovy.ast.expr.ExpressionTransformer; 80 import org.codehaus.groovy.ast.expr.FieldExpression; 81 import org.codehaus.groovy.ast.expr.GStringExpression; 82 import org.codehaus.groovy.ast.expr.ListExpression; 83 import org.codehaus.groovy.ast.expr.MapEntryExpression; 84 import org.codehaus.groovy.ast.expr.MapExpression; 85 import org.codehaus.groovy.ast.expr.MethodCallExpression; 86 import org.codehaus.groovy.ast.expr.NegationExpression; 87 import org.codehaus.groovy.ast.expr.NotExpression; 88 import org.codehaus.groovy.ast.expr.PostfixExpression; 89 import org.codehaus.groovy.ast.expr.PrefixExpression; 90 import org.codehaus.groovy.ast.expr.PropertyExpression; 91 import org.codehaus.groovy.ast.expr.RangeExpression; 92 import org.codehaus.groovy.ast.expr.RegexExpression; 93 import org.codehaus.groovy.ast.expr.StaticMethodCallExpression; 94 import org.codehaus.groovy.ast.expr.TernaryExpression; 95 import org.codehaus.groovy.ast.expr.TupleExpression; 96 import org.codehaus.groovy.ast.expr.VariableExpression; 97 import org.codehaus.groovy.ast.stmt.AssertStatement; 98 import org.codehaus.groovy.ast.stmt.BlockStatement; 99 import org.codehaus.groovy.ast.stmt.BreakStatement; 100 import org.codehaus.groovy.ast.stmt.CaseStatement; 101 import org.codehaus.groovy.ast.stmt.CatchStatement; 102 import org.codehaus.groovy.ast.stmt.ContinueStatement; 103 import org.codehaus.groovy.ast.stmt.DoWhileStatement; 104 import org.codehaus.groovy.ast.stmt.ExpressionStatement; 105 import org.codehaus.groovy.ast.stmt.ForStatement; 106 import org.codehaus.groovy.ast.stmt.IfStatement; 107 import org.codehaus.groovy.ast.stmt.ReturnStatement; 108 import org.codehaus.groovy.ast.stmt.Statement; 109 import org.codehaus.groovy.ast.stmt.SwitchStatement; 110 import org.codehaus.groovy.ast.stmt.SynchronizedStatement; 111 import org.codehaus.groovy.ast.stmt.ThrowStatement; 112 import org.codehaus.groovy.ast.stmt.TryCatchStatement; 113 import org.codehaus.groovy.ast.stmt.WhileStatement; 114 import org.codehaus.groovy.runtime.InvokerHelper; 115 import org.codehaus.groovy.syntax.Token; 116 import org.codehaus.groovy.syntax.Types; 117 import org.codehaus.groovy.syntax.parser.RuntimeParserException; 118 import org.objectweb.asm.ClassVisitor; 119 import org.objectweb.asm.CodeVisitor; 120 import org.objectweb.asm.Constants; 121 import org.objectweb.asm.Label; 122 123 130 public class AsmClassGenerator extends ClassGenerator { 131 132 private Logger log = Logger.getLogger(getClass().getName()); 133 134 private ClassVisitor cw; 135 private CodeVisitor cv; 136 private GeneratorContext context; 137 138 private String sourceFile; 139 140 private ClassNode classNode; 142 private ClassNode outermostClass; 143 private String internalClassName; 144 private String internalBaseClassName; 145 146 147 private Map variableStack = new HashMap (); 148 149 150 private boolean outputReturn; 151 152 153 private boolean leftHandExpression; 154 155 MethodCaller invokeMethodMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeMethod"); 157 MethodCaller invokeMethodSafeMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeMethodSafe"); 158 MethodCaller invokeStaticMethodMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeStaticMethod"); 159 MethodCaller invokeConstructorMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeConstructor"); 160 MethodCaller invokeConstructorOfMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeConstructorOf"); 161 MethodCaller invokeNoArgumentsConstructorOf = MethodCaller.newStatic(InvokerHelper.class, "invokeNoArgumentsConstructorOf"); 162 MethodCaller invokeClosureMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeClosure"); 163 MethodCaller invokeSuperMethodMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeSuperMethod"); 164 MethodCaller invokeNoArgumentsMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeNoArgumentsMethod"); 165 MethodCaller invokeStaticNoArgumentsMethod = 166 MethodCaller.newStatic(InvokerHelper.class, "invokeStaticNoArgumentsMethod"); 167 168 MethodCaller asIntMethod = MethodCaller.newStatic(InvokerHelper.class, "asInt"); 169 MethodCaller asTypeMethod = MethodCaller.newStatic(InvokerHelper.class, "asType"); 170 MethodCaller getPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "getProperty"); 171 MethodCaller getPropertySafeMethod = MethodCaller.newStatic(InvokerHelper.class, "getPropertySafe"); 172 MethodCaller setPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "setProperty"); 173 MethodCaller setPropertyMethod2 = MethodCaller.newStatic(InvokerHelper.class, "setProperty2"); 174 MethodCaller setPropertySafeMethod2 = MethodCaller.newStatic(InvokerHelper.class, "setPropertySafe2"); 175 MethodCaller getGroovyObjectPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "getGroovyObjectProperty"); 176 MethodCaller setGroovyObjectPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "setGroovyObjectProperty"); 177 MethodCaller asIteratorMethod = MethodCaller.newStatic(InvokerHelper.class, "asIterator"); 178 MethodCaller asBool = MethodCaller.newStatic(InvokerHelper.class, "asBool"); 179 MethodCaller notBoolean = MethodCaller.newStatic(InvokerHelper.class, "notBoolean"); 180 MethodCaller notObject = MethodCaller.newStatic(InvokerHelper.class, "notObject"); 181 MethodCaller regexPattern = MethodCaller.newStatic(InvokerHelper.class, "regexPattern"); 182 MethodCaller negation = MethodCaller.newStatic(InvokerHelper.class, "negate"); 183 184 MethodCaller compareIdenticalMethod = MethodCaller.newStatic(InvokerHelper.class, "compareIdentical"); 185 MethodCaller compareEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareEqual"); 186 MethodCaller compareNotEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareNotEqual"); 187 MethodCaller compareToMethod = MethodCaller.newStatic(InvokerHelper.class, "compareTo"); 188 MethodCaller findRegexMethod = MethodCaller.newStatic(InvokerHelper.class, "findRegex"); 189 MethodCaller matchRegexMethod = MethodCaller.newStatic(InvokerHelper.class, "matchRegex"); 190 MethodCaller compareLessThanMethod = MethodCaller.newStatic(InvokerHelper.class, "compareLessThan"); 191 MethodCaller compareLessThanEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareLessThanEqual"); 192 MethodCaller compareGreaterThanMethod = MethodCaller.newStatic(InvokerHelper.class, "compareGreaterThan"); 193 MethodCaller compareGreaterThanEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareGreaterThanEqual"); 194 MethodCaller isCaseMethod = MethodCaller.newStatic(InvokerHelper.class, "isCase"); 195 196 MethodCaller createListMethod = MethodCaller.newStatic(InvokerHelper.class, "createList"); 197 MethodCaller createTupleMethod = MethodCaller.newStatic(InvokerHelper.class, "createTuple"); 198 MethodCaller createMapMethod = MethodCaller.newStatic(InvokerHelper.class, "createMap"); 199 MethodCaller createRangeMethod = MethodCaller.newStatic(InvokerHelper.class, "createRange"); 200 201 MethodCaller assertFailedMethod = MethodCaller.newStatic(InvokerHelper.class, "assertFailed"); 202 203 MethodCaller iteratorNextMethod = MethodCaller.newInterface(Iterator .class, "next"); 204 MethodCaller iteratorHasNextMethod = MethodCaller.newInterface(Iterator .class, "hasNext"); 205 206 private int lastVariableIndex; 208 private static int tempVariableNameCounter; 209 210 private List exceptionBlocks = new ArrayList (); 212 213 private boolean definingParameters; 214 private Set syntheticStaticFields = new HashSet (); 215 private Set mutableVars = new HashSet (); 216 private boolean passingClosureParams; 217 218 private ConstructorNode constructorNode; 219 private MethodNode methodNode; 220 private BlockScope scope; 222 private BytecodeHelper helper = new BytecodeHelper(null); 223 224 private VariableScope variableScope; 225 226 public AsmClassGenerator( 227 GeneratorContext context, 228 ClassVisitor classVisitor, 229 ClassLoader classLoader, 230 String sourceFile) { 231 super(classLoader); 232 this.context = context; 233 this.cw = classVisitor; 234 this.sourceFile = sourceFile; 235 } 236 237 public void visitClass(ClassNode classNode) { 240 try { 241 syntheticStaticFields.clear(); 242 this.classNode = classNode; 243 this.outermostClass = null; 244 this.internalClassName = BytecodeHelper.getClassInternalName(classNode.getName()); 245 246 248 classNode.setSuperClass(checkValidType(classNode.getSuperClass(), classNode, "Must be a valid base class")); 250 String [] interfaces = classNode.getInterfaces(); 251 for (int i = 0; i < interfaces.length; i++ ) { 252 interfaces[i] = checkValidType(interfaces[i], classNode, "Must be a valid interface name"); 253 } 254 255 this.internalBaseClassName = BytecodeHelper.getClassInternalName(classNode.getSuperClass()); 256 257 cw.visit( 258 asmJDKVersion, 259 classNode.getModifiers(), 260 internalClassName, 261 internalBaseClassName, 262 BytecodeHelper.getClassInternalNames(classNode.getInterfaces()), 263 sourceFile); 264 265 273 classNode.visitContents(this); 274 275 createSyntheticStaticFields(); 276 277 for (Iterator iter = innerClasses.iterator(); iter.hasNext();) { 278 ClassNode innerClass = (ClassNode) iter.next(); 279 String innerClassName = innerClass.getName(); 280 String innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassName); 281 String outerClassName = internalClassName; MethodNode enclosingMethod = innerClass.getEnclosingMethod(); 283 if (enclosingMethod != null) { 284 outerClassName = null; 286 } 287 cw.visitInnerClass( 288 innerClassInternalName, 289 outerClassName, 290 innerClassName, 291 innerClass.getModifiers()); 292 } 293 cw.visitEnd(); 295 } 296 catch (GroovyRuntimeException e) { 297 e.setModule(classNode.getModule()); 298 throw e; 299 } 300 } 301 302 public void visitConstructor(ConstructorNode node) { 303 306 this.constructorNode = node; 307 this.methodNode = null; 308 this.variableScope = null; 309 310 visitParameters(node, node.getParameters()); 311 312 String methodType = BytecodeHelper.getMethodDescriptor("void", node.getParameters()); 313 cv = cw.visitMethod(node.getModifiers(), "<init>", methodType, null, null); 314 helper = new BytecodeHelper(cv); 315 316 findMutableVariables(); 317 resetVariableStack(node.getParameters()); 318 319 Statement code = node.getCode(); 320 if (code == null || !firstStatementIsSuperInit(code)) { 321 cv.visitVarInsn(ALOAD, 0); 323 cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "()V"); 324 } 325 if (code != null) { 326 code.visit(this); 327 } 328 329 cv.visitInsn(RETURN); 330 cv.visitMaxs(0, 0); 331 } 332 333 public void visitMethod(MethodNode node) { 334 this.constructorNode = null; 337 this.methodNode = node; 338 this.variableScope = null; 339 340 visitParameters(node, node.getParameters()); 341 node.setReturnType(checkValidType(node.getReturnType(), node, "Must be a valid return type")); 342 343 String methodType = BytecodeHelper.getMethodDescriptor(node.getReturnType(), node.getParameters()); 344 cv = cw.visitMethod(node.getModifiers(), node.getName(), methodType, null, null); 345 Label labelStart = new Label(); 346 cv.visitLabel(labelStart); 347 helper = new BytecodeHelper(cv); 348 349 findMutableVariables(); 350 resetVariableStack(node.getParameters()); 351 352 outputReturn = false; 353 354 node.getCode().visit(this); 355 356 if (!outputReturn) { 357 cv.visitInsn(RETURN); 358 } 359 360 for (Iterator iter = exceptionBlocks.iterator(); iter.hasNext();) { 362 Runnable runnable = (Runnable ) iter.next(); 363 runnable.run(); 364 } 365 exceptionBlocks.clear(); 366 367 Label labelEnd = new Label(); 368 cv.visitLabel(labelEnd); 369 370 380 cv.visitMaxs(0, 0); 381 } 382 383 protected void visitParameters(ASTNode node, Parameter[] parameters) { 384 for (int i = 0, size = parameters.length; i < size; i++ ) { 385 visitParameter(node, parameters[i]); 386 } 387 } 388 389 protected void visitParameter(ASTNode node, Parameter parameter) { 390 if (! parameter.isDynamicType()) { 391 parameter.setType(checkValidType(parameter.getType(), node, "Must be a valid parameter class")); 392 } 393 } 394 395 public void visitField(FieldNode fieldNode) { 396 onLineNumber(fieldNode); 397 398 fieldNode.setType(checkValidType(fieldNode.getType(), fieldNode, "Must be a valid field class for field: " + fieldNode.getName())); 400 401 404 Object fieldValue = null; 405 Expression expression = fieldNode.getInitialValueExpression(); 406 if (expression instanceof ConstantExpression) { 407 ConstantExpression constantExp = (ConstantExpression) expression; 408 Object value = constantExp.getValue(); 409 if (isPrimitiveFieldType(fieldNode.getType())) { 410 Class type = null; 412 try { 413 type = loadClass(fieldNode.getType()); 414 fieldValue = InvokerHelper.asType(value, type); 415 } 416 catch (Exception e) { 417 log.warning("Caught unexpected: " + e); 418 } 419 } 420 } 421 cw.visitField( 422 fieldNode.getModifiers(), 423 fieldNode.getName(), 424 BytecodeHelper.getTypeDescription(fieldNode.getType()), 425 fieldValue, 426 null); 427 } 428 429 432 public void visitProperty(PropertyNode statement) { 433 onLineNumber(statement); 434 this.methodNode = null; 436 } 437 438 441 444 public void visitForLoop(ForStatement loop) { 445 onLineNumber(loop); 446 447 448 451 Type variableType = checkValidType(loop.getVariableType(), loop, "for loop variable"); 452 Variable variable = defineVariable(loop.getVariable(), variableType, true); 453 454 if( isInScriptBody() ) { 455 variable.setProperty( true ); 456 } 457 458 459 462 loop.getCollectionExpression().visit(this); 463 464 asIteratorMethod.call(cv); 465 466 final int iteratorIdx = defineVariable(createVariableName("iterator"), "java.util.Iterator", false).getIndex(); 467 cv.visitVarInsn(ASTORE, iteratorIdx); 468 469 pushBlockScope(); 470 471 Label continueLabel = scope.getContinueLabel(); 472 cv.visitJumpInsn(GOTO, continueLabel); 473 Label label2 = new Label(); 474 cv.visitLabel(label2); 475 476 BytecodeExpression expression = new BytecodeExpression() { 477 public void visit(GroovyCodeVisitor visitor) { 478 cv.visitVarInsn(ALOAD, iteratorIdx); 479 480 iteratorNextMethod.call(cv); 481 } 482 }; 483 484 evaluateEqual( BinaryExpression.newAssignmentExpression(loop.getVariable(), expression) ); 485 486 487 490 loop.getLoopBlock().visit(this); 491 492 493 496 cv.visitLabel(continueLabel); 497 cv.visitVarInsn(ALOAD, iteratorIdx); 498 499 iteratorHasNextMethod.call(cv); 500 501 cv.visitJumpInsn(IFNE, label2); 502 503 cv.visitLabel(scope.getBreakLabel()); 504 popScope(); 505 } 506 507 public void visitWhileLoop(WhileStatement loop) { 508 onLineNumber(loop); 509 510 514 515 pushBlockScope(); 516 517 Label continueLabel = scope.getContinueLabel(); 518 519 cv.visitJumpInsn(GOTO, continueLabel); 520 Label l1 = new Label(); 521 cv.visitLabel(l1); 522 523 loop.getLoopBlock().visit(this); 524 525 cv.visitLabel(continueLabel); 526 528 loop.getBooleanExpression().visit(this); 529 530 cv.visitJumpInsn(IFNE, l1); 531 532 cv.visitLabel(scope.getBreakLabel()); 533 popScope(); 534 } 535 536 public void visitDoWhileLoop(DoWhileStatement loop) { 537 onLineNumber(loop); 538 539 pushBlockScope(); 540 541 Label breakLabel = scope.getBreakLabel(); 542 543 Label continueLabel = scope.getContinueLabel(); 544 cv.visitLabel(continueLabel); 545 Label l1 = new Label(); 546 547 loop.getLoopBlock().visit(this); 548 549 cv.visitLabel(l1); 550 551 loop.getBooleanExpression().visit(this); 552 553 cv.visitJumpInsn(IFNE, continueLabel); 554 555 cv.visitLabel(breakLabel); 556 popScope(); 557 } 558 559 public void visitIfElse(IfStatement ifElse) { 560 onLineNumber(ifElse); 561 562 ifElse.getBooleanExpression().visit(this); 563 564 Label l0 = new Label(); 565 cv.visitJumpInsn(IFEQ, l0); 566 ifElse.getIfBlock().visit(this); 567 568 Label l1 = new Label(); 569 cv.visitJumpInsn(GOTO, l1); 570 cv.visitLabel(l0); 571 572 ifElse.getElseBlock().visit(this); 573 cv.visitLabel(l1); 574 } 575 576 public void visitTernaryExpression(TernaryExpression expression) { 577 onLineNumber(expression); 578 579 expression.getBooleanExpression().visit(this); 580 581 Label l0 = new Label(); 582 cv.visitJumpInsn(IFEQ, l0); 583 expression.getTrueExpression().visit(this); 584 585 Label l1 = new Label(); 586 cv.visitJumpInsn(GOTO, l1); 587 cv.visitLabel(l0); 588 589 expression.getFalseExpression().visit(this); 590 cv.visitLabel(l1); 591 } 592 593 public void visitAssertStatement(AssertStatement statement) { 594 onLineNumber(statement); 595 596 599 BooleanExpression booleanExpression = statement.getBooleanExpression(); 600 booleanExpression.visit(this); 601 602 Label l0 = new Label(); 603 cv.visitJumpInsn(IFEQ, l0); 604 605 607 Label l1 = new Label(); 608 cv.visitJumpInsn(GOTO, l1); 609 cv.visitLabel(l0); 610 611 String expressionText = booleanExpression.getText(); 613 List list = new ArrayList (); 614 addVariableNames(booleanExpression, list); 615 if (list.isEmpty()) { 616 cv.visitLdcInsn(expressionText); 617 } 618 else { 619 boolean first = true; 620 621 cv.visitTypeInsn(NEW, "java/lang/StringBuffer"); 623 cv.visitInsn(DUP); 624 cv.visitLdcInsn(expressionText + ". Values: "); 625 626 cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "(Ljava/lang/String;)V"); 627 628 int tempIndex = defineVariable(createVariableName("assert"), "java.lang.Object", false).getIndex(); 629 630 cv.visitVarInsn(ASTORE, tempIndex); 631 632 for (Iterator iter = list.iterator(); iter.hasNext();) { 633 String name = (String ) iter.next(); 634 String text = name + " = "; 635 if (first) { 636 first = false; 637 } 638 else { 639 text = ", " + text; 640 } 641 642 cv.visitVarInsn(ALOAD, tempIndex); 643 cv.visitLdcInsn(text); 644 cv.visitMethodInsn( 645 INVOKEVIRTUAL, 646 "java/lang/StringBuffer", 647 "append", 648 "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 649 cv.visitInsn(POP); 650 651 cv.visitVarInsn(ALOAD, tempIndex); 652 new VariableExpression(name).visit(this); 653 cv.visitMethodInsn( 654 INVOKEVIRTUAL, 655 "java/lang/StringBuffer", 656 "append", 657 "(Ljava/lang/Object;)Ljava/lang/StringBuffer;"); 658 cv.visitInsn(POP); 659 660 } 661 cv.visitVarInsn(ALOAD, tempIndex); 662 } 663 664 statement.getMessageExpression().visit(this); 666 667 assertFailedMethod.call(cv); 668 cv.visitLabel(l1); 669 } 670 671 private void addVariableNames(Expression expression, List list) { 672 if (expression instanceof BooleanExpression) { 673 BooleanExpression boolExp = (BooleanExpression) expression; 674 addVariableNames(boolExp.getExpression(), list); 675 } 676 else if (expression instanceof BinaryExpression) { 677 BinaryExpression binExp = (BinaryExpression) expression; 678 addVariableNames(binExp.getLeftExpression(), list); 679 addVariableNames(binExp.getRightExpression(), list); 680 } 681 else if (expression instanceof VariableExpression) { 682 VariableExpression varExp = (VariableExpression) expression; 683 list.add(varExp.getVariable()); 684 } 685 } 686 687 public void visitTryCatchFinally(TryCatchStatement statement) { 688 onLineNumber(statement); 689 690 CatchStatement catchStatement = statement.getCatchStatement(0); 691 692 Statement tryStatement = statement.getTryStatement(); 693 694 if (tryStatement.isEmpty() || catchStatement == null) { 695 final Label l0 = new Label(); 696 cv.visitLabel(l0); 697 698 tryStatement.visit(this); 699 700 int index1 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex(); 701 int index2 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex(); 702 703 final Label l1 = new Label(); 704 cv.visitJumpInsn(JSR, l1); 705 final Label l2 = new Label(); 706 cv.visitLabel(l2); 707 final Label l3 = new Label(); 708 cv.visitJumpInsn(GOTO, l3); 709 final Label l4 = new Label(); 710 cv.visitLabel(l4); 711 cv.visitVarInsn(ASTORE, index1); 712 cv.visitJumpInsn(JSR, l1); 713 final Label l5 = new Label(); 714 cv.visitLabel(l5); 715 cv.visitVarInsn(ALOAD, index1); 716 cv.visitInsn(ATHROW); 717 cv.visitLabel(l1); 718 cv.visitVarInsn(ASTORE, index2); 719 720 statement.getFinallyStatement().visit(this); 721 722 cv.visitVarInsn(RET, index2); 723 cv.visitLabel(l3); 724 725 exceptionBlocks.add(new Runnable () { 726 public void run() { 727 cv.visitTryCatchBlock(l0, l2, l4, null); 728 cv.visitTryCatchBlock(l4, l5, l4, null); 729 } 730 }); 731 732 } 733 else { 734 String exceptionVar = catchStatement.getVariable(); 735 String exceptionType = 736 checkValidType(catchStatement.getExceptionType(), catchStatement, "in catch statement"); 737 738 int exceptionIndex = defineVariable(exceptionVar, exceptionType, false).getIndex(); 739 int index2 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex(); 740 int index3 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex(); 741 742 final Label l0 = new Label(); 743 cv.visitLabel(l0); 744 745 tryStatement.visit(this); 746 747 final Label l1 = new Label(); 748 cv.visitLabel(l1); 749 Label l2 = new Label(); 750 cv.visitJumpInsn(JSR, l2); 751 final Label l3 = new Label(); 752 cv.visitLabel(l3); 753 Label l4 = new Label(); 754 cv.visitJumpInsn(GOTO, l4); 755 final Label l5 = new Label(); 756 cv.visitLabel(l5); 757 758 cv.visitVarInsn(ASTORE, exceptionIndex); 759 760 if (catchStatement != null) { 761 catchStatement.visit(this); 762 } 763 764 cv.visitJumpInsn(JSR, l2); 765 final Label l6 = new Label(); 766 cv.visitLabel(l6); 767 cv.visitJumpInsn(GOTO, l4); 768 769 final Label l7 = new Label(); 770 cv.visitLabel(l7); 771 cv.visitVarInsn(ASTORE, index2); 772 cv.visitJumpInsn(JSR, l2); 773 774 final Label l8 = new Label(); 775 cv.visitLabel(l8); 776 cv.visitVarInsn(ALOAD, index2); 777 cv.visitInsn(ATHROW); 778 cv.visitLabel(l2); 779 cv.visitVarInsn(ASTORE, index3); 780 781 statement.getFinallyStatement().visit(this); 782 783 cv.visitVarInsn(RET, index3); 784 cv.visitLabel(l4); 785 786 788 final String exceptionTypeInternalName = 792 (catchStatement != null) ? BytecodeHelper.getClassInternalName(exceptionType) : null; 793 794 exceptionBlocks.add(new Runnable () { 795 public void run() { 796 cv.visitTryCatchBlock(l0, l1, l5, exceptionTypeInternalName); 797 cv.visitTryCatchBlock(l0, l3, l7, null); 798 cv.visitTryCatchBlock(l5, l6, l7, null); 799 cv.visitTryCatchBlock(l7, l8, l7, null); 800 } 801 }); 802 } 803 } 804 805 public void visitSwitch(SwitchStatement statement) { 806 onLineNumber(statement); 807 808 statement.getExpression().visit(this); 809 810 pushBlockScope(false, true); 812 scope.setContinueLabel(scope.getParent().getContinueLabel()); 813 814 815 int switchVariableIndex = defineVariable(createVariableName("switch"), "java.lang.Object").getIndex(); 816 cv.visitVarInsn(ASTORE, switchVariableIndex); 817 818 List caseStatements = statement.getCaseStatements(); 819 int caseCount = caseStatements.size(); 820 Label[] labels = new Label[caseCount + 1]; 821 for (int i = 0; i < caseCount; i++) { 822 labels[i] = new Label(); 823 } 824 825 int i = 0; 826 for (Iterator iter = caseStatements.iterator(); iter.hasNext(); i++) { 827 CaseStatement caseStatement = (CaseStatement) iter.next(); 828 visitCaseStatement(caseStatement, switchVariableIndex, labels[i], labels[i + 1]); 829 } 830 831 statement.getDefaultStatement().visit(this); 832 833 cv.visitLabel(scope.getBreakLabel()); 834 835 popScope(); 836 } 837 838 public void visitCaseStatement(CaseStatement statement) { 839 } 840 841 public void visitCaseStatement( 842 CaseStatement statement, 843 int switchVariableIndex, 844 Label thisLabel, 845 Label nextLabel) { 846 847 onLineNumber(statement); 848 849 cv.visitVarInsn(ALOAD, switchVariableIndex); 850 statement.getExpression().visit(this); 851 852 isCaseMethod.call(cv); 853 854 Label l0 = new Label(); 855 cv.visitJumpInsn(IFEQ, l0); 856 857 cv.visitLabel(thisLabel); 858 859 statement.getCode().visit(this); 860 861 if (nextLabel != null) { 864 cv.visitJumpInsn(GOTO, nextLabel); 865 } 866 867 cv.visitLabel(l0); 868 } 869 870 public void visitBreakStatement(BreakStatement statement) { 871 onLineNumber(statement); 872 873 cv.visitJumpInsn(GOTO, scope.getBreakLabel()); 874 } 875 876 public void visitContinueStatement(ContinueStatement statement) { 877 onLineNumber(statement); 878 879 cv.visitJumpInsn(GOTO, scope.getContinueLabel()); 880 } 881 882 public void visitSynchronizedStatement(SynchronizedStatement statement) { 883 onLineNumber(statement); 884 885 statement.getExpression().visit(this); 886 887 int index = defineVariable(createVariableName("synchronized"), "java.lang.Integer").getIndex(); 888 889 cv.visitVarInsn(ASTORE, index); 890 cv.visitInsn(MONITORENTER); 891 final Label l0 = new Label(); 892 cv.visitLabel(l0); 893 894 statement.getCode().visit(this); 895 896 cv.visitVarInsn(ALOAD, index); 897 cv.visitInsn(MONITOREXIT); 898 final Label l1 = new Label(); 899 cv.visitJumpInsn(GOTO, l1); 900 final Label l2 = new Label(); 901 cv.visitLabel(l2); 902 cv.visitVarInsn(ALOAD, index); 903 cv.visitInsn(MONITOREXIT); 904 cv.visitInsn(ATHROW); 905 cv.visitLabel(l1); 906 907 exceptionBlocks.add(new Runnable () { 908 public void run() { 909 cv.visitTryCatchBlock(l0, l2, l2, null); 910 } 911 }); 912 } 913 914 public void visitThrowStatement(ThrowStatement statement) { 915 statement.getExpression().visit(this); 916 917 cv.visitTypeInsn(CHECKCAST, "java/lang/Throwable"); 919 920 cv.visitInsn(ATHROW); 921 } 922 923 public void visitReturnStatement(ReturnStatement statement) { 924 onLineNumber(statement); 925 String returnType = methodNode.getReturnType(); 926 if (returnType.equals("void")) { 927 if (!(statement == ReturnStatement.RETURN_NULL_OR_VOID)) { 928 throw new RuntimeParserException( 929 "Cannot use return statement with an expression on a method that returns void", 930 statement); 931 932 } 933 cv.visitInsn(RETURN); 934 outputReturn = true; 935 return; 936 } 937 938 Expression expression = statement.getExpression(); 939 evaluateExpression(expression); 940 941 helper.unbox(returnType); 945 if (returnType.equals("double")) { 946 cv.visitInsn(DRETURN); 947 } 948 else if (returnType.equals("float")) { 949 cv.visitInsn(FRETURN); 950 } 951 else if (returnType.equals("long")) { 952 cv.visitInsn(LRETURN); 953 } 954 else if (returnType.equals("boolean")) { 955 cv.visitInsn(IRETURN); 956 } 957 else if ( 958 returnType.equals("char") 959 || returnType.equals("byte") 960 || returnType.equals("int") 961 || returnType.equals("short")) { cv.visitInsn(IRETURN); 964 } 965 else { 966 doConvertAndCast(returnType, expression); 967 cv.visitInsn(ARETURN); 968 969 986 } 987 988 outputReturn = true; 989 } 990 991 994 protected void doConvertAndCast(String type, Expression expression) { 995 String expType = getExpressionType(expression); 996 997 if (isValidTypeForCast(type) && (expType == null || !type.equals(expType))) { 998 doConvertAndCast(type); 999 } 1000 } 1001 1002 1005 protected void evaluateExpression(Expression expression) { 1006 visitAndAutobox(expression); 1007 1009 Expression assignExpr = createReturnLHSExpression(expression); 1010 if (assignExpr != null) { 1011 leftHandExpression = false; 1012 assignExpr.visit(this); 1013 } 1014 } 1015 1016 public void visitExpressionStatement(ExpressionStatement statement) { 1017 onLineNumber(statement); 1018 1019 Expression expression = statement.getExpression(); 1020 visitAndAutobox(expression); 1021 1022 if (isPopRequired(expression)) { 1023 cv.visitInsn(POP); 1024 } 1025 } 1026 1027 1030 public void visitBinaryExpression(BinaryExpression expression) { 1031 switch (expression.getOperation().getType()) { 1032 case Types.EQUAL : 1033 evaluateEqual(expression); 1034 break; 1035 1036 case Types.COMPARE_IDENTICAL : 1037 evaluateBinaryExpression(compareIdenticalMethod, expression); 1038 break; 1039 1040 case Types.COMPARE_EQUAL : 1041 evaluateBinaryExpression(compareEqualMethod, expression); 1042 break; 1043 1044 case Types.COMPARE_NOT_EQUAL : 1045 evaluateBinaryExpression(compareNotEqualMethod, expression); 1046 break; 1047 1048 case Types.COMPARE_TO : 1049 evaluateCompareTo(expression); 1050 break; 1051 1052 case Types.COMPARE_GREATER_THAN : 1053 evaluateBinaryExpression(compareGreaterThanMethod, expression); 1054 break; 1055 1056 case Types.COMPARE_GREATER_THAN_EQUAL : 1057 evaluateBinaryExpression(compareGreaterThanEqualMethod, expression); 1058 break; 1059 1060 case Types.COMPARE_LESS_THAN : 1061 evaluateBinaryExpression(compareLessThanMethod, expression); 1062 break; 1063 1064 case Types.COMPARE_LESS_THAN_EQUAL : 1065 evaluateBinaryExpression(compareLessThanEqualMethod, expression); 1066 break; 1067 1068 case Types.LOGICAL_AND : 1069 evaluateLogicalAndExpression(expression); 1070 break; 1071 1072 case Types.LOGICAL_OR : 1073 evaluateLogicalOrExpression(expression); 1074 break; 1075 1076 case Types.PLUS : 1077 evaluateBinaryExpression("plus", expression); 1078 break; 1079 1080 case Types.PLUS_EQUAL : 1081 evaluateBinaryExpressionWithAsignment("plus", expression); 1082 break; 1083 1084 case Types.MINUS : 1085 evaluateBinaryExpression("minus", expression); 1086 break; 1087 1088 case Types.MINUS_EQUAL : 1089 evaluateBinaryExpressionWithAsignment("minus", expression); 1090 break; 1091 1092 case Types.MULTIPLY : 1093 evaluateBinaryExpression("multiply", expression); 1094 break; 1095 1096 case Types.MULTIPLY_EQUAL : 1097 evaluateBinaryExpressionWithAsignment("multiply", expression); 1098 break; 1099 1100 case Types.DIVIDE : 1101 evaluateBinaryExpression("div", expression); 1104 break; 1105 1106 case Types.DIVIDE_EQUAL : 1107 evaluateBinaryExpressionWithAsignment("div", expression); 1110 break; 1111 1112 case Types.INTDIV : 1113 evaluateBinaryExpression("intdiv", expression); 1114 break; 1115 1116 case Types.INTDIV_EQUAL : 1117 evaluateBinaryExpressionWithAsignment("intdiv", expression); 1118 break; 1119 1120 case Types.MOD : 1121 evaluateBinaryExpression("mod", expression); 1122 break; 1123 1124 case Types.MOD_EQUAL : 1125 evaluateBinaryExpressionWithAsignment("mod", expression); 1126 break; 1127 1128 case Types.LEFT_SHIFT : 1129 evaluateBinaryExpression("leftShift", expression); 1130 break; 1131 1132 case Types.RIGHT_SHIFT : 1133 evaluateBinaryExpression("rightShift", expression); 1134 break; 1135 1136 case Types.RIGHT_SHIFT_UNSIGNED : 1137 evaluateBinaryExpression("rightShiftUnsigned", expression); 1138 break; 1139 1140 case Types.KEYWORD_INSTANCEOF : 1141 evaluateInstanceof(expression); 1142 break; 1143 1144 case Types.FIND_REGEX : 1145 evaluateBinaryExpression(findRegexMethod, expression); 1146 break; 1147 1148 case Types.MATCH_REGEX : 1149 evaluateBinaryExpression(matchRegexMethod, expression); 1150 break; 1151 1152 case Types.LEFT_SQUARE_BRACKET : 1153 if (leftHandExpression) { 1154 throw new RuntimeException ("Should not be called"); 1155 } 1157 else { 1158 evaluateBinaryExpression("getAt", expression); 1159 } 1160 break; 1161 1162 default : 1163 throw new ClassGeneratorException("Operation: " + expression.getOperation() + " not supported"); 1164 } 1165 } 1166 1167 public void visitPostfixExpression(PostfixExpression expression) { 1168 switch (expression.getOperation().getType()) { 1169 case Types.PLUS_PLUS : 1170 evaluatePostfixMethod("next", expression.getExpression()); 1171 break; 1172 case Types.MINUS_MINUS : 1173 evaluatePostfixMethod("previous", expression.getExpression()); 1174 break; 1175 } 1176 } 1177 1178 public void visitPrefixExpression(PrefixExpression expression) { 1179 switch (expression.getOperation().getType()) { 1180 case Types.PLUS_PLUS : 1181 evaluatePrefixMethod("next", expression.getExpression()); 1182 break; 1183 case Types.MINUS_MINUS : 1184 evaluatePrefixMethod("previous", expression.getExpression()); 1185 break; 1186 } 1187 } 1188 1189 public void visitClosureExpression(ClosureExpression expression) { 1190 ClassNode innerClass = createClosureClass(expression); 1191 addInnerClass(innerClass); 1192 String innerClassinternalName = BytecodeHelper.getClassInternalName(innerClass.getName()); 1193 1194 ClassNode owner = innerClass.getOuterClass(); 1195 String ownerTypeName = owner.getName(); 1196 if (classNode.isStaticClass() || isStaticMethod()) { 1197 ownerTypeName = "java.lang.Class"; 1198 } 1199 1200 passingClosureParams = true; 1201 List constructors = innerClass.getDeclaredConstructors(); 1202 ConstructorNode node = (ConstructorNode) constructors.get(0); 1203 Parameter[] localVariableParams = node.getParameters(); 1204 1205 1206 1212 for (int i = 2; i < localVariableParams.length; i++) { 1213 Parameter param = localVariableParams[i]; 1214 String name = param.getName(); 1215 1216 if (variableStack.get(name) == null && classNode.getField(name) == null) { 1217 defineVariable(name, "java.lang.Object"); 1218 } 1219 } 1220 1221 cv.visitTypeInsn(NEW, innerClassinternalName); 1222 cv.visitInsn(DUP); 1223 if (isStaticMethod() || classNode.isStaticClass()) { 1224 visitClassExpression(new ClassExpression(ownerTypeName)); 1225 } 1226 else { 1227 loadThisOrOwner(); 1228 } 1229 1230 if (innerClass.getSuperClass().equals("groovy.lang.Closure")) { 1231 if (isStaticMethod()) { 1232 1236 visitClassExpression(new ClassExpression(ownerTypeName)); 1237 } 1238 else { 1239 loadThisOrOwner(); 1240 } 1241 } 1242 1243 1245 for (int i = 2; i < localVariableParams.length; i++) { 1247 Parameter param = localVariableParams[i]; 1248 String name = param.getName(); 1249 1250 if (variableStack.get(name) == null) { 1251 visitFieldExpression(new FieldExpression(classNode.getField(name))); 1252 } 1253 else { 1254 visitVariableExpression(new VariableExpression(name)); 1255 } 1256 } 1258 passingClosureParams = false; 1259 1260 cv.visitMethodInsn( 1263 INVOKESPECIAL, 1264 innerClassinternalName, 1265 "<init>", 1266 BytecodeHelper.getMethodDescriptor("void", localVariableParams)); 1267 } 1268 1269 1272 protected void loadThisOrOwner() { 1273 if (isInnerClass()) { 1274 visitFieldExpression(new FieldExpression(classNode.getField("owner"))); 1275 } 1276 else { 1277 cv.visitVarInsn(ALOAD, 0); 1278 } 1279 } 1280 1281 public void visitRegexExpression(RegexExpression expression) { 1282 expression.getRegex().visit(this); 1283 regexPattern.call(cv); 1284 } 1285 1286 1290 public void visitConstantExpression(ConstantExpression expression) { 1291 Object value = expression.getValue(); 1292 if (value == null) { 1293 cv.visitInsn(ACONST_NULL); 1294 } 1295 else if (value instanceof String ) { 1296 cv.visitLdcInsn(value); 1297 } 1298 else if (value instanceof Number ) { 1299 1300 Number n = (Number ) value; 1301 String className = BytecodeHelper.getClassInternalName(value.getClass().getName()); 1302 cv.visitTypeInsn(NEW, className); 1303 cv.visitInsn(DUP); 1304 String methodType; 1305 if (n instanceof Double ) { 1306 cv.visitLdcInsn(n); 1307 methodType = "(D)V"; 1308 } 1309 else if (n instanceof Float ) { 1310 cv.visitLdcInsn(n); 1311 methodType = "(F)V"; 1312 } 1313 else if (value instanceof Long ) { 1314 cv.visitLdcInsn(n); 1315 methodType = "(J)V"; 1316 } 1317 else if (value instanceof BigDecimal ) { 1318 cv.visitLdcInsn(n.toString()); 1319 methodType = "(Ljava/lang/String;)V"; 1320 } 1321 else if (value instanceof BigInteger ) { 1322 cv.visitLdcInsn(n.toString()); 1323 methodType = "(Ljava/lang/String;)V"; 1324 } 1325 else if (value instanceof Integer ){ 1326 cv.visitLdcInsn(n); 1327 methodType = "(I)V"; 1328 } 1329 else 1330 { 1331 throw new ClassGeneratorException( 1332 "Cannot generate bytecode for constant: " + value 1333 + " of type: " + value.getClass().getName() 1334 +". Numeric constant type not supported."); 1335 } 1336 1337 cv.visitMethodInsn(INVOKESPECIAL, className, "<init>", methodType); 1338 } 1339 else if (value instanceof Boolean ) { 1340 Boolean bool = (Boolean ) value; 1341 String text = (bool.booleanValue()) ? "TRUE" : "FALSE"; 1342 cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", text, "Ljava/lang/Boolean;"); 1343 } 1344 else if (value instanceof Class ) { 1345 Class vc = (Class ) value; 1346 if (!vc.getName().equals("java.lang.Void")) { 1347 throw new ClassGeneratorException( 1348 "Cannot generate bytecode for constant: " + value + " of type: " + value.getClass().getName()); 1349 } 1350 } 1351 else { 1352 throw new ClassGeneratorException( 1353 "Cannot generate bytecode for constant: " + value + " of type: " + value.getClass().getName()); 1354 } 1355 } 1356 1357 public void visitNegationExpression(NegationExpression expression) { 1358 Expression subExpression = expression.getExpression(); 1359 subExpression.visit(this); 1360 negation.call(cv); 1361 } 1362 1363 public void visitCastExpression(CastExpression expression) { 1364 String type = expression.getType(); 1365 type = checkValidType(type, expression, "in cast"); 1366 1367 visitAndAutobox(expression.getExpression()); 1368 1369 doConvertAndCast(type, expression.getExpression()); 1370 } 1371 1372 public void visitNotExpression(NotExpression expression) { 1373 Expression subExpression = expression.getExpression(); 1374 subExpression.visit(this); 1375 1376 if (comparisonExpression(expression.getExpression())) { 1381 notBoolean.call(cv); 1382 } 1383 else { 1384 notObject.call(cv); 1385 } 1386 } 1387 1388 public void visitBooleanExpression(BooleanExpression expression) { 1389 expression.getExpression().visit(this); 1390 1391 if (!comparisonExpression(expression.getExpression())) { 1392 asBool.call(cv); 1393 } 1394 } 1395 1396 public void visitMethodCallExpression(MethodCallExpression call) { 1397 this.leftHandExpression = false; 1398 1399 Expression arguments = call.getArguments(); 1400 1406 boolean superMethodCall = MethodCallExpression.isSuperMethodCall(call); 1407 String method = call.getMethod(); 1408 if (superMethodCall && method.equals("<init>")) { 1409 1410 cv.visitVarInsn(ALOAD, 0); 1411 if (isInClosureConstructor()) { cv.visitVarInsn(ALOAD, 2); 1413 cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "(Ljava/lang/Object;)V"); 1414 } 1415 else { 1416 cv.visitVarInsn(ALOAD, 1); 1417 cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "(Ljava/lang/Object;)V"); 1418 } 1419 } 1420 else { 1421 if (isThisExpression(call.getObjectExpression()) && isFieldOrVariable(call.getMethod())) { 1423 1430 1431 visitVariableExpression(new VariableExpression(method)); 1433 arguments.visit(this); 1434 invokeClosureMethod.call(cv); 1435 } 1436 else { 1437 if (superMethodCall) { 1438 if (method.equals("super") || method.equals("<init>")) { 1439 ConstructorNode superConstructorNode = findSuperConstructor(call); 1440 1441 cv.visitVarInsn(ALOAD, 0); 1442 1443 loadArguments(superConstructorNode.getParameters(), arguments); 1444 1445 String descriptor = BytecodeHelper.getMethodDescriptor("void", superConstructorNode.getParameters()); 1446 cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(classNode.getSuperClass()), "<init>", descriptor); 1447 } 1448 else { 1449 MethodNode superMethodNode = findSuperMethod(call); 1450 1451 cv.visitVarInsn(ALOAD, 0); 1452 1453 loadArguments(superMethodNode.getParameters(), arguments); 1454 1455 String descriptor = BytecodeHelper.getMethodDescriptor(superMethodNode.getReturnType(), superMethodNode.getParameters()); 1456 cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(superMethodNode.getDeclaringClass().getName()), method, descriptor); 1457 } 1458 } 1459 else { 1460 if (emptyArguments(arguments) && !call.isSafe()) { 1461 call.getObjectExpression().visit(this); 1462 cv.visitLdcInsn(method); 1463 invokeNoArgumentsMethod.call(cv); 1464 } 1465 else { 1466 if (argumentsUseStack(arguments)) { 1467 int paramIdx = 1468 defineVariable(createVariableName("temp"), "java.lang.Object", false).getIndex(); 1469 1470 arguments.visit(this); 1471 1472 cv.visitVarInsn(ASTORE, paramIdx); 1473 1474 call.getObjectExpression().visit(this); 1475 1476 cv.visitLdcInsn(method); 1477 1478 cv.visitVarInsn(ALOAD, paramIdx); 1479 } 1480 else { 1481 call.getObjectExpression().visit(this); 1482 cv.visitLdcInsn(method); 1483 arguments.visit(this); 1484 } 1485 1486 if (call.isSafe()) { 1487 invokeMethodSafeMethod.call(cv); 1488 } 1489 else { 1490 invokeMethodMethod.call(cv); 1491 } 1492 } 1493 } 1494 } 1495 } 1496 } 1497 1498 1501 protected void loadArguments(Parameter[] parameters, Expression expression) { 1502 TupleExpression argListExp = (TupleExpression) expression; 1503 List arguments = argListExp.getExpressions(); 1504 for (int i = 0, size = arguments.size(); i < size; i++) { 1505 Expression argExp = argListExp.getExpression(i); 1506 Parameter param = parameters[i]; 1507 visitAndAutobox(argExp); 1508 1509 String type = param.getType(); 1510 if (BytecodeHelper.isPrimitiveType(type)) { 1511 helper.unbox(type); 1512 } 1513 doConvertAndCast(type, argExp); 1514 } 1515 } 1516 1517 1520 protected MethodNode findSuperMethod(MethodCallExpression call) { 1521 String methodName = call.getMethod(); 1522 TupleExpression argExpr = (TupleExpression) call.getArguments(); 1523 int argCount = argExpr.getExpressions().size(); 1524 ClassNode superClassNode = classNode.getSuperClassNode(); 1525 if (superClassNode != null) { 1526 List methods = superClassNode.getMethods(methodName); 1527 for (Iterator iter = methods.iterator(); iter.hasNext(); ) { 1528 MethodNode method = (MethodNode) iter.next(); 1529 if (method.getParameters().length == argCount) { 1530 return method; 1531 } 1532 } 1533 } 1534 throw new GroovyRuntimeException("No such method: " + methodName + " for class: " + classNode.getName(), call); 1535 } 1536 1537 1540 protected ConstructorNode findSuperConstructor(MethodCallExpression call) { 1541 TupleExpression argExpr = (TupleExpression) call.getArguments(); 1542 int argCount = argExpr.getExpressions().size(); 1543 ClassNode superClassNode = classNode.getSuperClassNode(); 1544 if (superClassNode != null) { 1545 List constructors = superClassNode.getDeclaredConstructors(); 1546 for (Iterator iter = constructors.iterator(); iter.hasNext(); ) { 1547 ConstructorNode constructor = (ConstructorNode) iter.next(); 1548 if (constructor.getParameters().length == argCount) { 1549 return constructor; 1550 } 1551 } 1552 } 1553 throw new GroovyRuntimeException("No such constructor for class: " + classNode.getName(), call); 1554 } 1555 1556 protected boolean emptyArguments(Expression arguments) { 1557 if (arguments instanceof TupleExpression) { 1558 TupleExpression tupleExpression = (TupleExpression) arguments; 1559 int size = tupleExpression.getExpressions().size(); 1560 return size == 0; 1561 } 1562 return false; 1563 } 1564 1565 public void visitStaticMethodCallExpression(StaticMethodCallExpression call) { 1566 this.leftHandExpression = false; 1567 1568 Expression arguments = call.getArguments(); 1569 if (emptyArguments(arguments)) { 1570 cv.visitLdcInsn(call.getType()); 1571 cv.visitLdcInsn(call.getMethod()); 1572 1573 invokeStaticNoArgumentsMethod.call(cv); 1574 } 1575 else { 1576 if (arguments instanceof TupleExpression) { 1577 TupleExpression tupleExpression = (TupleExpression) arguments; 1578 int size = tupleExpression.getExpressions().size(); 1579 if (size == 1) { 1580 arguments = (Expression) tupleExpression.getExpressions().get(0); 1581 } 1582 } 1583 1584 cv.visitLdcInsn(call.getType()); 1585 cv.visitLdcInsn(call.getMethod()); 1586 arguments.visit(this); 1587 1588 invokeStaticMethodMethod.call(cv); 1589 } 1590 } 1591 1592 public void visitConstructorCallExpression(ConstructorCallExpression call) { 1593 this.leftHandExpression = false; 1594 1595 Expression arguments = call.getArguments(); 1596 if (arguments instanceof TupleExpression) { 1597 TupleExpression tupleExpression = (TupleExpression) arguments; 1598 int size = tupleExpression.getExpressions().size(); 1599 if (size == 0) { 1600 arguments = null; 1601 } 1602 else if (size == 1) { 1603 arguments = (Expression) tupleExpression.getExpressions().get(0); 1604 } 1605 } 1606 1607 String type = checkValidType(call.getType(), call, "in constructor call"); 1609 1610 1612 visitClassExpression(new ClassExpression(type)); 1613 if (arguments !=null) { 1614 arguments.visit(this); 1615 invokeConstructorOfMethod.call(cv); 1616 } else { 1617 invokeNoArgumentsConstructorOf.call(cv); 1618 } 1619 1626 } 1627 1628 public void visitPropertyExpression(PropertyExpression expression) { 1629 1630 String className = checkForQualifiedClass(expression); 1632 if (className != null) { 1633 visitClassExpression(new ClassExpression(className)); 1634 return; 1635 } 1636 Expression objectExpression = expression.getObjectExpression(); 1637 if (expression.getProperty().equals("class")) { 1638 if ((objectExpression instanceof ClassExpression)) { 1639 visitClassExpression((ClassExpression) objectExpression); 1640 return; 1641 } 1642 else if (objectExpression instanceof VariableExpression) { 1643 VariableExpression varExp = (VariableExpression) objectExpression; 1644 className = varExp.getVariable(); 1645 try { 1646 className = resolveClassName(className); 1647 visitClassExpression(new ClassExpression(className)); 1648 return; 1649 } 1650 catch (Exception e) { 1651 } 1653 } 1654 } 1655 1656 if (isThisExpression(objectExpression)) { 1657 String name = expression.getProperty(); 1659 FieldNode field = classNode.getField(name); 1660 if (field != null) { 1661 visitFieldExpression(new FieldExpression(field)); 1662 return; 1663 } 1664 } 1665 1666 boolean left = leftHandExpression; 1667 leftHandExpression = false; 1670 1671 objectExpression.visit(this); 1672 1673 cv.visitLdcInsn(expression.getProperty()); 1674 1675 if (isGroovyObject(objectExpression) && ! expression.isSafe()) { 1676 if (left) { 1677 setGroovyObjectPropertyMethod.call(cv); 1678 } 1679 else { 1680 getGroovyObjectPropertyMethod.call(cv); 1681 } 1682 } 1683 else { 1684 if (expression.isSafe()) { 1685 if (left) { 1686 setPropertySafeMethod2.call(cv); 1687 } 1688 else { 1689 getPropertySafeMethod.call(cv); 1690 } 1691 } 1692 else { 1693 if (left) { 1694 setPropertyMethod2.call(cv); 1695 } 1696 else { 1697 getPropertyMethod.call(cv); 1698 } 1699 } 1700 } 1701 } 1702 1703 protected boolean isGroovyObject(Expression objectExpression) { 1704 return isThisExpression(objectExpression); 1705 } 1706 1707 1711 protected String checkForQualifiedClass(PropertyExpression expression) { 1712 String text = expression.getText(); 1713 try { 1714 return resolveClassName(text); 1715 } 1716 catch (Exception e) { 1717 if (text.endsWith(".class")) { 1718 text = text.substring(0, text.length() - 6); 1719 try { 1720 return resolveClassName(text); 1721 } 1722 catch (Exception e2) { 1723 } 1724 } 1725 return null; 1726 } 1727 } 1728 1729 public void visitFieldExpression(FieldExpression expression) { 1730 FieldNode field = expression.getField(); 1731 boolean isStatic = field.isStatic(); 1732 1733 boolean holder = field.isHolder() && !isInClosureConstructor(); 1734 if (!isStatic && !leftHandExpression) { 1735 cv.visitVarInsn(ALOAD, 0); 1736 } 1737 String type = field.getType(); 1738 int tempIndex = defineVariable(createVariableName("field"), "java.lang.Object", false).getIndex(); 1739 1740 if (leftHandExpression && !holder) { 1741 if (isInClosureConstructor()) { 1742 helper.doCast(type); 1743 } 1744 else { 1745 doConvertAndCast(type); 1747 } 1748 } 1749 1750 String ownerName = 1751 (field.getOwner().equals(classNode.getName())) 1752 ? internalClassName 1753 : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner())); 1754 int opcode = isStatic ? GETSTATIC : GETFIELD; 1755 if (holder) { 1756 if (leftHandExpression) { 1757 cv.visitVarInsn(ASTORE, tempIndex); 1758 if (!isStatic) 1759 cv.visitVarInsn(ALOAD, 0); cv.visitFieldInsn(opcode, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type)); 1761 cv.visitVarInsn(ALOAD, tempIndex); 1763 cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V"); 1764 } 1765 else { 1766 cv.visitFieldInsn(opcode, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type)); 1767 cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;"); 1768 } 1769 } 1770 else { 1771 if (leftHandExpression) { 1772 if (!isStatic) { 1773 opcode = PUTFIELD; 1774 helper.store(field.getType(), tempIndex); 1775 cv.visitVarInsn(ALOAD, 0); helper.load(field.getType(), tempIndex); 1779 1780 } else { 1781 opcode = PUTSTATIC; 1782 } 1783 cv.visitFieldInsn(opcode, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type)); 1784 }else { 1785 cv.visitFieldInsn(opcode, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type)); 1786 if (BytecodeHelper.isPrimitiveType(type)) { 1787 helper.box(type); 1788 } 1789 } 1790 } 1791 } 1792 1793 protected void visitOuterFieldExpression(FieldExpression expression, ClassNode outerClassNode, int steps, boolean first ) { 1794 int valueIdx = defineVariable(createVariableName("temp"), "java.lang.Object", false).getIndex(); 1795 1796 if (leftHandExpression && first) { 1797 cv.visitVarInsn(ASTORE, valueIdx); 1798 } 1799 1800 FieldNode field = expression.getField(); 1801 boolean isStatic = field.isStatic(); 1802 1803 if (steps > 1 || !isStatic) { 1804 cv.visitVarInsn(ALOAD, 0); 1805 cv.visitFieldInsn( 1806 GETFIELD, 1807 internalClassName, 1808 "owner", 1809 BytecodeHelper.getTypeDescription(outerClassNode.getName())); 1810 } 1811 1812 if( steps == 1 ) { 1813 int opcode = (leftHandExpression) ? ((isStatic) ? PUTSTATIC : PUTFIELD) : ((isStatic) ? GETSTATIC : GETFIELD); 1814 String ownerName = BytecodeHelper.getClassInternalName(outerClassNode.getName()); 1815 1816 if (leftHandExpression) { 1817 cv.visitVarInsn(ALOAD, valueIdx); 1818 boolean holder = field.isHolder() && !isInClosureConstructor(); 1819 if ( !holder) { 1820 doConvertAndCast(field.getType()); 1821 } 1822 } 1823 cv.visitFieldInsn(opcode, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(field.getType())); 1824 if (!leftHandExpression) { 1825 if (BytecodeHelper.isPrimitiveType(field.getType())) { 1826 helper.box(field.getType()); 1827 } 1828 } 1829 } 1830 1831 else { 1832 visitOuterFieldExpression( expression, outerClassNode.getOuterClass(), steps - 1, false ); 1833 } 1834 } 1835 1836 1837 1838 1841 1842 public void visitVariableExpression(VariableExpression expression) { 1843 1844 String variableName = expression.getVariable(); 1845 1846 1849 1852 if (isStaticMethod() && variableName.equals("this")) { 1853 visitClassExpression(new ClassExpression(classNode.getName())); 1854 return; } 1856 1857 1860 if (variableName.equals("super")) { 1861 visitClassExpression(new ClassExpression(classNode.getSuperClass())); 1862 return; } 1864 1865 1866 1869 if (!variableName.equals("this")) { 1870 String className = resolveClassName(variableName); 1871 if (className != null) { 1872 if (leftHandExpression) { 1873 throw new RuntimeParserException( 1874 "Cannot use a class expression on the left hand side of an assignment", 1875 expression); 1876 } 1877 visitClassExpression(new ClassExpression(className)); 1878 return; } 1880 } 1881 1882 1883 1886 1887 1895 boolean handled = false; 1896 Variable variable = (Variable)variableStack.get( variableName ); 1897 1898 if( variable != null ) { 1899 1900 if( variable.isProperty() ) { 1901 processPropertyVariable( variableName, variable ); 1902 } 1903 else { 1904 processStackVariable( variableName, variable ); 1905 } 1906 1907 handled = true; 1908 } 1909 1910 1913 else { 1914 1915 int steps = 0; 1916 ClassNode current = classNode; 1917 FieldNode field = null; 1918 1919 do { 1920 if( (field = current.getField(variableName)) != null ) { 1921 break; 1922 } 1923 steps++; 1924 1925 } while( (current = current.getOuterClass()) != null ); 1926 1927 if( field != null ) { 1928 processFieldAccess( variableName, field, steps ); 1929 handled = true; 1930 } 1931 } 1932 1933 1934 1941 if( !handled ) { 1942 String variableType = expression.getType(); 1943 variable = defineVariable( variableName, variableType ); 1944 1945 if( isInScriptBody() || !leftHandExpression ) { 1946 variable.setProperty( true ); 1947 processPropertyVariable( variableName, variable ); 1948 } 1949 else { 1950 processStackVariable( variableName, variable ); 1951 } 1952 } 1953 } 1954 1955 1956 protected void processStackVariable( String name, Variable variable ) { 1957 String type = variable.getTypeName(); 1958 int index = variable.getIndex(); 1959 boolean holder = variable.isHolder() && !passingClosureParams; 1960 1961 if( leftHandExpression ) { 1962 if (holder) { 1963 int tempIndex = defineVariable(createVariableName("reference"), type, false).getIndex(); 1964 cv.visitVarInsn(ASTORE, tempIndex); 1965 cv.visitVarInsn(ALOAD, index); 1966 cv.visitVarInsn(ALOAD, tempIndex); 1968 cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V"); 1969 } 1970 else { 1971 helper.store("objref", index); } 1974 } 1975 else { 1976 if (holder) { 1977 cv.visitVarInsn(ALOAD, index); 1978 cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;"); 1979 } 1980 else { 1981 cv.visitVarInsn(ALOAD, index); 1982 } 1983 } 1984 1985 } 1986 1987 protected void processPropertyVariable( String name, Variable variable ) { 1988 if (variable.isHolder() && passingClosureParams && isInScriptBody() ) { 1989 cv.visitTypeInsn(NEW, "org/codehaus/groovy/runtime/ScriptReference"); 1991 cv.visitInsn(DUP); 1992 1993 loadThisOrOwner(); 1994 cv.visitLdcInsn(name); 1995 1996 cv.visitMethodInsn( 1997 INVOKESPECIAL, 1998 "org/codehaus/groovy/runtime/ScriptReference", 1999 "<init>", 2000 "(Lgroovy/lang/Script;Ljava/lang/String;)V"); 2001 } 2002 else { 2003 visitPropertyExpression(new PropertyExpression(VariableExpression.THIS_EXPRESSION, name)); 2004 } 2005 } 2006 2007 2008 protected void processFieldAccess( String name, FieldNode field, int steps ) { 2009 FieldExpression expression = new FieldExpression(field); 2010 2011 if( steps == 0 ) { 2012 visitFieldExpression( expression ); 2013 } 2014 else { 2015 visitOuterFieldExpression( expression, classNode.getOuterClass(), steps, true ); 2016 } 2017 } 2018 2019 2020 2021 2025 protected boolean isInScriptBody() { 2026 if (classNode.isScriptBody()) { 2027 return true; 2028 } 2029 else { 2030 return classNode.isScript() && methodNode != null && methodNode.getName().equals("run"); 2031 } 2032 } 2033 2034 2038 protected boolean isPopRequired(Expression expression) { 2039 if (expression instanceof MethodCallExpression) { 2040 return !MethodCallExpression.isSuperMethodCall((MethodCallExpression) expression); 2041 } 2042 if (expression instanceof BinaryExpression) { 2043 BinaryExpression binExp = (BinaryExpression) expression; 2044 switch (binExp.getOperation().getType()) { 2045 case Types.EQUAL : 2046 case Types.PLUS_EQUAL : 2047 case Types.MINUS_EQUAL : 2048 case Types.MULTIPLY_EQUAL : 2049 case Types.DIVIDE_EQUAL : 2050 case Types.INTDIV_EQUAL : 2051 case Types.MOD_EQUAL : 2052 return false; 2053 } 2054 } 2055 return true; 2056 } 2057 2058 protected boolean firstStatementIsSuperInit(Statement code) { 2059 ExpressionStatement expStmt = null; 2060 if (code instanceof ExpressionStatement) { 2061 expStmt = (ExpressionStatement) code; 2062 } 2063 else if (code instanceof BlockStatement) { 2064 BlockStatement block = (BlockStatement) code; 2065 if (!block.getStatements().isEmpty()) { 2066 Object expr = block.getStatements().get(0); 2067 if (expr instanceof ExpressionStatement) { 2068 expStmt = (ExpressionStatement) expr; 2069 } 2070 } 2071 } 2072 if (expStmt != null) { 2073 Expression expr = expStmt.getExpression(); 2074 if (expr instanceof MethodCallExpression) { 2075 MethodCallExpression call = (MethodCallExpression) expr; 2076 if (MethodCallExpression.isSuperMethodCall(call)) { 2077 return call.getMethod().equals("<init>") || call.getMethod().equals("super"); 2079 } 2080 } 2081 } 2082 return false; 2083 } 2084 2085 protected void createSyntheticStaticFields() { 2086 for (Iterator iter = syntheticStaticFields.iterator(); iter.hasNext();) { 2087 String staticFieldName = (String ) iter.next(); 2088 cw.visitField(ACC_STATIC + ACC_SYNTHETIC, staticFieldName, "Ljava/lang/Class;", null, null); 2090 } 2091 2092 if (!syntheticStaticFields.isEmpty()) { 2093 cv = 2094 cw.visitMethod( 2095 ACC_STATIC + ACC_SYNTHETIC, 2096 "class$", 2097 "(Ljava/lang/String;)Ljava/lang/Class;", 2098 null, 2099 null); 2100 helper = new BytecodeHelper(cv); 2101 2102 Label l0 = new Label(); 2103 cv.visitLabel(l0); 2104 cv.visitVarInsn(ALOAD, 0); 2105 cv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;"); 2106 Label l1 = new Label(); 2107 cv.visitLabel(l1); 2108 cv.visitInsn(ARETURN); 2109 Label l2 = new Label(); 2110 cv.visitLabel(l2); 2111 cv.visitVarInsn(ASTORE, 1); 2112 cv.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError"); 2113 cv.visitInsn(DUP); 2114 cv.visitVarInsn(ALOAD, 1); 2115 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassNotFoundException", "getMessage", "()Ljava/lang/String;"); 2116 cv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoClassDefFoundError", "<init>", "(Ljava/lang/String;)V"); 2117 cv.visitInsn(ATHROW); 2118 cv.visitTryCatchBlock(l0, l2, l2, "java/lang/ClassNotFoundException"); cv.visitMaxs(3, 2); 2120 2121 cw.visitEnd(); 2122 } 2123 } 2124 2125 public void visitClassExpression(ClassExpression expression) { 2126 String type = expression.getText(); 2127 2129 2130 if (BytecodeHelper.isPrimitiveType(type)) { 2131 String objectType = BytecodeHelper.getObjectTypeForPrimitive(type); 2132 cv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(objectType), "TYPE", "Ljava/lang/Class;"); 2133 } 2134 else { 2135 final String staticFieldName = 2136 (type.equals(classNode.getName())) ? "class$0" : "class$" + type.replace('.', '$'); 2137 2138 syntheticStaticFields.add(staticFieldName); 2139 2140 cv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;"); 2141 Label l0 = new Label(); 2142 cv.visitJumpInsn(IFNONNULL, l0); 2143 cv.visitLdcInsn(type); 2144 cv.visitMethodInsn(INVOKESTATIC, internalClassName, "class$", "(Ljava/lang/String;)Ljava/lang/Class;"); 2145 cv.visitInsn(DUP); 2146 cv.visitFieldInsn(PUTSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;"); 2147 Label l1 = new Label(); 2148 cv.visitJumpInsn(GOTO, l1); 2149 cv.visitLabel(l0); 2150 cv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;"); 2151 cv.visitLabel(l1); 2152 } 2153 } 2154 2155 public void visitRangeExpression(RangeExpression expression) { 2156 leftHandExpression = false; 2157 expression.getFrom().visit(this); 2158 2159 leftHandExpression = false; 2160 expression.getTo().visit(this); 2161 2162 helper.pushConstant(expression.isInclusive()); 2163 2164 createRangeMethod.call(cv); 2165 } 2166 2167 public void visitMapEntryExpression(MapEntryExpression expression) { 2168 } 2169 2170 public void visitMapExpression(MapExpression expression) { 2171 List entries = expression.getMapEntryExpressions(); 2172 int size = entries.size(); 2173 helper.pushConstant(size * 2); 2174 2175 cv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); 2176 2177 int i = 0; 2178 for (Iterator iter = entries.iterator(); iter.hasNext();) { 2179 MapEntryExpression entry = (MapEntryExpression) iter.next(); 2180 2181 cv.visitInsn(DUP); 2182 helper.pushConstant(i++); 2183 visitAndAutobox(entry.getKeyExpression()); 2184 cv.visitInsn(AASTORE); 2185 2186 cv.visitInsn(DUP); 2187 helper.pushConstant(i++); 2188 visitAndAutobox(entry.getValueExpression()); 2189 cv.visitInsn(AASTORE); 2190 } 2191 createMapMethod.call(cv); 2192 } 2193 2194 public void visitTupleExpression(TupleExpression expression) { 2195 int size = expression.getExpressions().size(); 2196 2197 helper.pushConstant(size); 2198 2199 cv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); 2200 2201 for (int i = 0; i < size; i++) { 2202 cv.visitInsn(DUP); 2203 helper.pushConstant(i); 2204 visitAndAutobox(expression.getExpression(i)); 2205 cv.visitInsn(AASTORE); 2206 } 2207 } 2209 2210 public void visitArrayExpression(ArrayExpression expression) { 2211 String type = expression.getType(); 2212 String typeName = BytecodeHelper.getClassInternalName(type); 2213 Expression sizeExpression = expression.getSizeExpression(); 2214 if (sizeExpression != null) { 2215 visitAndAutobox(sizeExpression); 2217 asIntMethod.call(cv); 2218 2219 cv.visitTypeInsn(ANEWARRAY, typeName); 2220 } 2221 else { 2222 int size = expression.getExpressions().size(); 2223 helper.pushConstant(size); 2224 2225 cv.visitTypeInsn(ANEWARRAY, typeName); 2226 2227 for (int i = 0; i < size; i++) { 2228 cv.visitInsn(DUP); 2229 helper.pushConstant(i); 2230 Expression elementExpression = expression.getExpression(i); 2231 if (elementExpression == null) { 2232 ConstantExpression.NULL.visit(this); 2233 } 2234 else { 2235 2236 if(!type.equals(elementExpression.getClass().getName())) { 2237 visitCastExpression(new CastExpression(type, elementExpression)); 2238 } 2239 else { 2240 visitAndAutobox(elementExpression); 2241 } 2242 } 2243 cv.visitInsn(AASTORE); 2244 } 2245 } 2246 } 2247 2248 public void visitListExpression(ListExpression expression) { 2249 int size = expression.getExpressions().size(); 2250 helper.pushConstant(size); 2251 2252 cv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); 2253 2254 for (int i = 0; i < size; i++) { 2255 cv.visitInsn(DUP); 2256 helper.pushConstant(i); 2257 visitAndAutobox(expression.getExpression(i)); 2258 cv.visitInsn(AASTORE); 2259 } 2260 createListMethod.call(cv); 2261 } 2262 2263 public void visitGStringExpression(GStringExpression expression) { 2264 int size = expression.getValues().size(); 2265 helper.pushConstant(size); 2266 2267 cv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); 2268 2269 for (int i = 0; i < size; i++) { 2270 cv.visitInsn(DUP); 2271 helper.pushConstant(i); 2272 visitAndAutobox(expression.getValue(i)); 2273 cv.visitInsn(AASTORE); 2274 } 2275 2276 int paramIdx = defineVariable(createVariableName("iterator"), "java.lang.Object", false).getIndex(); 2277 cv.visitVarInsn(ASTORE, paramIdx); 2278 2279 ClassNode innerClass = createGStringClass(expression); 2280 addInnerClass(innerClass); 2281 String innerClassinternalName = BytecodeHelper.getClassInternalName(innerClass.getName()); 2282 2283 cv.visitTypeInsn(NEW, innerClassinternalName); 2284 cv.visitInsn(DUP); 2285 cv.visitVarInsn(ALOAD, paramIdx); 2286 2287 cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName, "<init>", "([Ljava/lang/Object;)V"); 2288 } 2289 2290 protected boolean addInnerClass(ClassNode innerClass) { 2293 innerClass.setModule(classNode.getModule()); 2294 return innerClasses.add(innerClass); 2295 } 2296 2297 protected ClassNode createClosureClass(ClosureExpression expression) { 2298 ClassNode owner = getOutermostClass(); 2299 boolean parentIsInnerClass = owner instanceof InnerClassNode; 2300 String outerClassName = owner.getName(); 2301 String name = outerClassName + "$" 2302 + context.getNextClosureInnerName(owner, classNode, methodNode); boolean staticMethodOrInStaticClass = isStaticMethod() || classNode.isStaticClass(); 2304 if (staticMethodOrInStaticClass) { 2305 outerClassName = "java.lang.Class"; 2306 } 2307 Parameter[] parameters = expression.getParameters(); 2308 if (parameters == null || parameters.length == 0) { 2309 parameters = new Parameter[] { new Parameter("it")}; 2311 } 2312 2313 Parameter[] localVariableParams = getClosureSharedVariables(expression); 2314 2315 InnerClassNode answer = new InnerClassNode(owner, name, ACC_SUPER, "groovy.lang.Closure"); answer.setEnclosingMethod(this.methodNode); 2317 if (staticMethodOrInStaticClass) { 2318 answer.setStaticClass(true); 2319 } 2320 if (isInScriptBody()) { 2321 answer.setScriptBody(true); 2322 } 2323 MethodNode method = 2324 answer.addMethod("doCall", ACC_PUBLIC, "java.lang.Object", parameters, expression.getCode()); 2325 2326 method.setLineNumber(expression.getLineNumber()); 2327 method.setColumnNumber(expression.getColumnNumber()); 2328 2329 VariableScope varScope = expression.getVariableScope(); 2330 if (varScope == null) { 2331 throw new RuntimeException ( 2332 "Must have a VariableScope by now! for expression: " + expression + " class: " + name); 2333 } 2334 else { 2335 method.setVariableScope(varScope); 2336 } 2337 if (parameters.length > 1 2338 || (parameters.length == 1 2339 && parameters[0].getType() != null 2340 && !parameters[0].getType().equals("java.lang.Object"))) { 2341 2342 answer.addMethod( 2344 "call", 2345 ACC_PUBLIC, 2346 "java.lang.Object", 2347 parameters, 2348 new ReturnStatement( 2349 new MethodCallExpression( 2350 VariableExpression.THIS_EXPRESSION, 2351 "doCall", 2352 new ArgumentListExpression(parameters)))); 2353 } 2354 2355 FieldNode ownerField = answer.addField("owner", ACC_PRIVATE, outerClassName, null); 2356 2357 BlockStatement block = new BlockStatement(); 2359 block.addStatement( 2360 new ExpressionStatement( 2361 new MethodCallExpression( 2362 new VariableExpression("super"), 2363 "<init>", 2364 new VariableExpression("_outerInstance")))); 2365 block.addStatement( 2366 new ExpressionStatement( 2367 new BinaryExpression( 2368 new FieldExpression(ownerField), 2369 Token.newSymbol(Types.EQUAL, -1, -1), 2370 new VariableExpression("_outerInstance")))); 2371 2372 for (int i = 0; i < localVariableParams.length; i++) { 2374 Parameter param = localVariableParams[i]; 2375 String paramName = param.getName(); 2376 boolean holder = mutableVars.contains(paramName); 2377 Expression initialValue = null; 2378 String type = param.getType(); 2379 FieldNode paramField = null; 2380 if (holder) { 2381 initialValue = new VariableExpression(paramName); 2382 type = Reference.class.getName(); 2383 param.makeReference(); 2384 paramField = answer.addField(paramName, ACC_PRIVATE, type, initialValue); 2385 paramField.setHolder(true); 2386 String realType = param.getRealType(); 2387 String methodName = Verifier.capitalize(paramName); 2388 2389 Expression fieldExp = new FieldExpression(paramField); 2391 answer.addMethod( 2392 "get" + methodName, 2393 ACC_PUBLIC, 2394 realType, 2395 Parameter.EMPTY_ARRAY, 2396 new ReturnStatement(fieldExp)); 2397 2398 2407 } 2408 else { 2409 PropertyNode propertyNode = answer.addProperty(paramName, ACC_PUBLIC, type, initialValue, null, null); 2410 paramField = propertyNode.getField(); 2411 block.addStatement( 2412 new ExpressionStatement( 2413 new BinaryExpression( 2414 new FieldExpression(paramField), 2415 Token.newSymbol(Types.EQUAL, -1, -1), 2416 new VariableExpression(paramName)))); 2417 } 2418 } 2419 2420 Parameter[] params = new Parameter[2 + localVariableParams.length]; 2421 params[0] = new Parameter(outerClassName, "_outerInstance"); 2422 params[1] = new Parameter("java.lang.Object", "_delegate"); 2423 System.arraycopy(localVariableParams, 0, params, 2, localVariableParams.length); 2424 2425 answer.addConstructor(ACC_PUBLIC, params, block); 2426 return answer; 2427 } 2428 2429 protected ClassNode getOutermostClass() { 2430 if (outermostClass == null) { 2431 outermostClass = classNode; 2432 while (outermostClass instanceof InnerClassNode) { 2433 outermostClass = outermostClass.getOuterClass(); 2434 } 2435 } 2436 return outermostClass; 2437 } 2438 2439 protected ClassNode createGStringClass(GStringExpression expression) { 2440 ClassNode owner = classNode; 2441 if (owner instanceof InnerClassNode) { 2442 owner = owner.getOuterClass(); 2443 } 2444 String outerClassName = owner.getName(); 2445 String name = outerClassName + "$" + context.getNextInnerClassIdx(); 2446 InnerClassNode answer = new InnerClassNode(owner, name, ACC_SUPER, GString.class.getName()); 2447 answer.setEnclosingMethod(this.methodNode); 2448 FieldNode stringsField = 2449 answer.addField( 2450 "strings", 2451 ACC_PRIVATE , 2452 "java.lang.String[]", 2453 new ArrayExpression("java.lang.String", expression.getStrings())); 2454 answer.addMethod( 2455 "getStrings", 2456 ACC_PUBLIC, 2457 "java.lang.String[]", 2458 Parameter.EMPTY_ARRAY, 2459 new ReturnStatement(new FieldExpression(stringsField))); 2460 BlockStatement block = new BlockStatement(); 2462 block.addStatement( 2463 new ExpressionStatement( 2464 new MethodCallExpression(new VariableExpression("super"), "<init>", new VariableExpression("values")))); 2465 Parameter[] contructorParams = new Parameter[] { new Parameter("java.lang.Object[]", "values")}; 2466 answer.addConstructor(ACC_PUBLIC, contructorParams, block); 2467 return answer; 2468 } 2469 2470 protected void doConvertAndCast(String type) { 2471 if (!type.equals("java.lang.Object")) { 2472 2473 if (!type.endsWith("[]") && isValidTypeForCast(type)) { 2474 visitClassExpression(new ClassExpression(type)); 2475 asTypeMethod.call(cv); 2476 } 2477 2478 helper.doCast(type); 2479 } 2480 } 2481 2482 protected void evaluateLogicalOrExpression(BinaryExpression expression) { 2483 visitBooleanExpression(new BooleanExpression(expression.getLeftExpression())); 2484 Label l0 = new Label(); 2485 Label l2 = new Label(); 2486 cv.visitJumpInsn(IFEQ, l0); 2487 2488 cv.visitLabel(l2); 2489 2490 visitConstantExpression(ConstantExpression.TRUE); 2491 2492 Label l1 = new Label(); 2493 cv.visitJumpInsn(GOTO, l1); 2494 cv.visitLabel(l0); 2495 2496 visitBooleanExpression(new BooleanExpression(expression.getRightExpression())); 2497 2498 cv.visitJumpInsn(IFNE, l2); 2499 2500 visitConstantExpression(ConstantExpression.FALSE); 2501 cv.visitLabel(l1); 2502 } 2503 2504 protected void evaluateLogicalAndExpression(BinaryExpression expression) { 2505 visitBooleanExpression(new BooleanExpression(expression.getLeftExpression())); 2506 Label l0 = new Label(); 2507 cv.visitJumpInsn(IFEQ, l0); 2508 2509 visitBooleanExpression(new BooleanExpression(expression.getRightExpression())); 2510 2511 cv.visitJumpInsn(IFEQ, l0); 2512 2513 visitConstantExpression(ConstantExpression.TRUE); 2514 2515 Label l1 = new Label(); 2516 cv.visitJumpInsn(GOTO, l1); 2517 cv.visitLabel(l0); 2518 2519 visitConstantExpression(ConstantExpression.FALSE); 2520 2521 cv.visitLabel(l1); 2522 } 2523 2524 protected void evaluateBinaryExpression(String method, BinaryExpression expression) { 2525 Expression leftExpression = expression.getLeftExpression(); 2526 leftHandExpression = false; 2527 leftExpression.visit(this); 2528 cv.visitLdcInsn(method); 2529 leftHandExpression = false; 2530 new ArgumentListExpression(new Expression[] { expression.getRightExpression()}).visit(this); 2531 invokeMethodMethod.call(cv); 2533 } 2534 2535 protected void evaluateCompareTo(BinaryExpression expression) { 2536 Expression leftExpression = expression.getLeftExpression(); 2537 leftHandExpression = false; 2538 leftExpression.visit(this); 2539 expression.getRightExpression().visit(this); 2540 compareToMethod.call(cv); 2541 } 2542 2543 protected void evaluateBinaryExpressionWithAsignment(String method, BinaryExpression expression) { 2544 Expression leftExpression = expression.getLeftExpression(); 2545 if (leftExpression instanceof BinaryExpression) { 2546 BinaryExpression leftBinExpr = (BinaryExpression) leftExpression; 2547 if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) { 2548 2554 MethodCallExpression methodCall = 2555 new MethodCallExpression( 2556 expression.getLeftExpression(), 2557 method, 2558 new ArgumentListExpression(new Expression[] { expression.getRightExpression()})); 2559 2560 Expression safeIndexExpr = createReusableExpression(leftBinExpr.getRightExpression()); 2561 2562 visitMethodCallExpression( 2563 new MethodCallExpression( 2564 leftBinExpr.getLeftExpression(), 2565 "putAt", 2566 new ArgumentListExpression(new Expression[] { safeIndexExpr, methodCall }))); 2567 cv.visitInsn(POP); 2568 return; 2569 } 2570 } 2571 2572 evaluateBinaryExpression(method, expression); 2573 2574 leftHandExpression = true; 2575 evaluateExpression(leftExpression); 2576 leftHandExpression = false; 2577 } 2578 2579 protected void evaluateBinaryExpression(MethodCaller compareMethod, BinaryExpression expression) { 2580 Expression leftExpression = expression.getLeftExpression(); 2581 2586 2587 leftHandExpression = false; 2588 2589 evaluateExpression(leftExpression); 2590 leftHandExpression = false; 2591 evaluateExpression(expression.getRightExpression()); 2592 compareMethod.call(cv); 2594 } 2595 2596 protected void evaluateEqual(BinaryExpression expression) { 2597 Expression leftExpression = expression.getLeftExpression(); 2598 if (leftExpression instanceof BinaryExpression) { 2599 BinaryExpression leftBinExpr = (BinaryExpression) leftExpression; 2600 if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) { 2601 visitMethodCallExpression( 2607 new MethodCallExpression( 2608 leftBinExpr.getLeftExpression(), 2609 "putAt", 2610 new ArgumentListExpression( 2611 new Expression[] { leftBinExpr.getRightExpression(), expression.getRightExpression()}))); 2612 cv.visitInsn(POP); 2613 return; 2614 } 2615 } 2616 2618 leftHandExpression = false; 2620 Expression rightExpression = expression.getRightExpression(); 2621 2622 String type = getLHSType(leftExpression); 2623 if (type != null) { 2624 2627 if (BytecodeHelper.isPrimitiveType(type)) { 2629 rightExpression.visit(this); 2630 } 2631 else { 2632 visitCastExpression(new CastExpression(type, rightExpression)); 2633 } 2634 } 2635 else { 2636 visitAndAutobox(rightExpression); 2637 } 2638 2639 leftHandExpression = true; 2640 leftExpression.visit(this); 2641 leftHandExpression = false; 2642 } 2643 2644 2649 protected String getLHSType(Expression leftExpression) { 2650 if (leftExpression instanceof VariableExpression) { 2651 VariableExpression varExp = (VariableExpression) leftExpression; 2652 String type = varExp.getType(); 2653 if (isValidTypeForCast(type)) { 2654 return type; 2655 } 2656 String variableName = varExp.getVariable(); 2657 Variable variable = (Variable) variableStack.get(variableName); 2658 if (variable != null) { 2659 if (variable.isHolder() || variable.isProperty()) { 2660 return null; 2661 } 2662 type = variable.getTypeName(); 2663 if (isValidTypeForCast(type)) { 2664 return type; 2665 } 2666 } 2667 else { 2668 FieldNode field = classNode.getField(variableName); 2669 if (field == null) { 2670 field = classNode.getOuterField(variableName); 2671 } 2672 if (field != null) { 2673 type = field.getType(); 2674 if (!field.isHolder() && isValidTypeForCast(type)) { 2675 return type; 2676 } 2677 } 2678 } 2679 } 2680 return null; 2681 } 2682 2683 protected boolean isValidTypeForCast(String type) { 2684 return type != null && !type.equals("java.lang.Object") && !type.equals("groovy.lang.Reference") && !BytecodeHelper.isPrimitiveType(type); 2685 } 2686 2687 protected void visitAndAutobox(Expression expression) { 2688 expression.visit(this); 2689 2690 if (comparisonExpression(expression)) { 2691 Label l0 = new Label(); 2692 cv.visitJumpInsn(IFEQ, l0); 2693 cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;"); 2694 Label l1 = new Label(); 2695 cv.visitJumpInsn(GOTO, l1); 2696 cv.visitLabel(l0); 2697 cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;"); 2698 cv.visitLabel(l1); 2699 } 2700 } 2701 2702 protected void evaluatePrefixMethod(String method, Expression expression) { 2703 if (isNonStaticField(expression) && ! isHolderVariable(expression) && !isStaticMethod()) { 2704 cv.visitVarInsn(ALOAD, 0); 2705 } 2706 expression.visit(this); 2707 cv.visitLdcInsn(method); 2708 invokeNoArgumentsMethod.call(cv); 2709 2710 leftHandExpression = true; 2711 expression.visit(this); 2712 leftHandExpression = false; 2713 expression.visit(this); 2714 } 2715 2716 protected void evaluatePostfixMethod(String method, Expression expression) { 2717 leftHandExpression = false; 2721 expression.visit(this); 2722 2723 int tempIdx = defineVariable(createVariableName("postfix"), "java.lang.Object", false).getIndex(); 2724 cv.visitVarInsn(ASTORE, tempIdx); 2725 cv.visitVarInsn(ALOAD, tempIdx); 2726 2727 cv.visitLdcInsn(method); 2728 invokeNoArgumentsMethod.call(cv); 2729 2730 leftHandExpression = true; 2731 expression.visit(this); 2732 leftHandExpression = false; 2733 2734 cv.visitVarInsn(ALOAD, tempIdx); 2735 } 2736 2737 protected boolean isHolderVariable(Expression expression) { 2738 if (expression instanceof FieldExpression) { 2739 FieldExpression fieldExp = (FieldExpression) expression; 2740 return fieldExp.getField().isHolder(); 2741 } 2742 if (expression instanceof VariableExpression) { 2743 VariableExpression varExp = (VariableExpression) expression; 2744 Variable variable = (Variable) variableStack.get(varExp.getVariable()); 2745 if (variable != null) { 2746 return variable.isHolder(); 2747 } 2748 FieldNode field = classNode.getField(varExp.getVariable()); 2749 if (field != null) { 2750 return field.isHolder(); 2751 } 2752 } 2753 return false; 2754 } 2755 2756 protected void evaluateInstanceof(BinaryExpression expression) { 2757 expression.getLeftExpression().visit(this); 2758 Expression rightExp = expression.getRightExpression(); 2759 String className = null; 2760 if (rightExp instanceof ClassExpression) { 2761 ClassExpression classExp = (ClassExpression) rightExp; 2762 className = classExp.getType(); 2763 } 2764 else { 2765 throw new RuntimeException ( 2766 "Right hand side of the instanceof keyworld must be a class name, not: " + rightExp); 2767 } 2768 className = checkValidType(className, expression, "Must be a valid type name for an instanceof statement"); 2769 String classInternalName = BytecodeHelper.getClassInternalName(className); 2770 cv.visitTypeInsn(INSTANCEOF, classInternalName); 2771 } 2772 2773 2778 protected boolean argumentsUseStack(Expression arguments) { 2779 return arguments instanceof TupleExpression || arguments instanceof ClosureExpression; 2780 } 2781 2782 2785 protected boolean isNonStaticField(Expression expression) { 2786 FieldNode field = null; 2787 if (expression instanceof VariableExpression) { 2788 VariableExpression varExp = (VariableExpression) expression; 2789 field = classNode.getField(varExp.getVariable()); 2790 } 2791 else if (expression instanceof FieldExpression) { 2792 FieldExpression fieldExp = (FieldExpression) expression; 2793 field = classNode.getField(fieldExp.getFieldName()); 2794 } 2795 else if (expression instanceof PropertyExpression) { 2796 PropertyExpression fieldExp = (PropertyExpression) expression; 2797 field = classNode.getField(fieldExp.getProperty()); 2798 } 2799 if (field != null) { 2800 return !field.isStatic(); 2801 } 2802 return false; 2803 } 2804 2805 protected boolean isThisExpression(Expression expression) { 2806 if (expression instanceof VariableExpression) { 2807 VariableExpression varExp = (VariableExpression) expression; 2808 return varExp.getVariable().equals("this"); 2809 } 2810 return false; 2811 } 2812 2813 2817 protected Expression createReturnLHSExpression(Expression expression) { 2818 if (expression instanceof BinaryExpression) { 2819 BinaryExpression binExpr = (BinaryExpression) expression; 2820 if (binExpr.getOperation().isA(Types.ASSIGNMENT_OPERATOR)) { 2821 return createReusableExpression(binExpr.getLeftExpression()); 2822 } 2823 } 2824 return null; 2825 } 2826 2827 protected Expression createReusableExpression(Expression expression) { 2828 ExpressionTransformer transformer = new ExpressionTransformer() { 2829 public Expression transform(Expression expression) { 2830 if (expression instanceof PostfixExpression) { 2831 PostfixExpression postfixExp = (PostfixExpression) expression; 2832 return postfixExp.getExpression(); 2833 } 2834 else if (expression instanceof PrefixExpression) { 2835 PrefixExpression prefixExp = (PrefixExpression) expression; 2836 return prefixExp.getExpression(); 2837 } 2838 return expression; 2839 } 2840 }; 2841 2842 return transformer.transform(expression.transformExpression(transformer)); 2844 } 2845 2846 protected boolean comparisonExpression(Expression expression) { 2847 if (expression instanceof BinaryExpression) { 2848 BinaryExpression binExpr = (BinaryExpression) expression; 2849 switch (binExpr.getOperation().getType()) { 2850 case Types.COMPARE_EQUAL : 2851 case Types.MATCH_REGEX : 2852 case Types.COMPARE_GREATER_THAN : 2853 case Types.COMPARE_GREATER_THAN_EQUAL : 2854 case Types.COMPARE_LESS_THAN : 2855 case Types.COMPARE_LESS_THAN_EQUAL : 2856 case Types.COMPARE_IDENTICAL : 2857 case Types.COMPARE_NOT_EQUAL : 2858 case Types.KEYWORD_INSTANCEOF : 2859 return true; 2860 } 2861 } 2862 else if (expression instanceof BooleanExpression) { 2863 return true; 2864 } 2865 return false; 2866 } 2867 2868 protected void onLineNumber(ASTNode statement) { 2869 int number = statement.getLineNumber(); 2870 if (number >= 0 && cv != null) { 2871 Label l = new Label(); 2872 cv.visitLabel(l); 2873 cv.visitLineNumber(number, l); 2874 } 2875 } 2876 2877 protected VariableScope getVariableScope() { 2878 if (variableScope == null) { 2879 if (methodNode != null) { 2880 variableScope = methodNode.getVariableScope(); 2882 if (variableScope == null) { 2883 variableScope = new VariableScope(); 2884 methodNode.setVariableScope(variableScope); 2885 VariableScopeCodeVisitor visitor = new VariableScopeCodeVisitor(variableScope); 2886 visitor.setParameters(methodNode.getParameters()); 2887 Statement code = methodNode.getCode(); 2888 if (code != null) { 2889 code.visit(visitor); 2890 } 2891 } 2892 addFieldsToVisitor(variableScope); 2893 } 2894 else if (constructorNode != null) { 2895 variableScope = new VariableScope(); 2896 constructorNode.setVariableScope(variableScope); 2897 VariableScopeCodeVisitor visitor = new VariableScopeCodeVisitor(variableScope); 2898 visitor.setParameters(constructorNode.getParameters()); 2899 Statement code = constructorNode.getCode(); 2900 if (code != null) { 2901 code.visit(visitor); 2902 } 2903 addFieldsToVisitor(variableScope); 2904 } 2905 else { 2906 throw new RuntimeException ("Can't create a variable scope outside of a method or constructor"); 2907 } 2908 } 2909 return variableScope; 2910 } 2911 2912 2916 protected Parameter[] getClosureSharedVariables(ClosureExpression expression) { 2917 List vars = new ArrayList (); 2918 2919 2924 VariableScope outerScope = getVariableScope().createRecursiveParentScope(); 2925 VariableScope innerScope = expression.getVariableScope(); 2926 if (innerScope == null) { 2927 System.out.println( 2928 "No variable scope for: " + expression + " method: " + methodNode + " constructor: " + constructorNode); 2929 innerScope = new VariableScope(getVariableScope()); 2930 } 2931 else { 2932 innerScope = innerScope.createRecursiveChildScope(); 2933 } 2934 2935 2936 2945 Set outerDecls = outerScope.getDeclaredVariables(); 2946 Set outerRefs = outerScope.getReferencedVariables(); 2947 Set innerDecls = innerScope.getDeclaredVariables(); 2948 Set innerRefs = innerScope.getReferencedVariables(); 2949 2950 2951 2965 Set varSet = new HashSet (); 2966 for (Iterator iter = innerRefs.iterator(); iter.hasNext();) { 2967 String var = (String ) iter.next(); 2968 if (outerDecls.contains(var) && (isNotFieldOfOutermostClass(var))) { 2970 String type = getVariableType(var); 2971 vars.add(new Parameter(type, var)); 2972 varSet.add(var); 2973 } 2974 } 2975 for (Iterator iter = outerRefs.iterator(); iter.hasNext();) { 2976 String var = (String ) iter.next(); 2977 if (innerDecls.contains(var) && (isNotFieldOfOutermostClass(var)) && !varSet.contains(var)) { 2979 String type = getVariableType(var); 2980 vars.add(new Parameter(type, var)); 2981 } 2982 } 2983 2984 2985 Parameter[] answer = new Parameter[vars.size()]; 2986 vars.toArray(answer); 2987 return answer; 2988 } 2989 2990 protected boolean isNotFieldOfOutermostClass(String var) { 2991 return getOutermostClass().getField(var) == null; 2993 } 2994 2995 protected void findMutableVariables() { 2996 3004 VariableScope outerScope = getVariableScope(); 3005 3006 VariableScope innerScope = outerScope.createCompositeChildScope(); 3008 3009 Set outerDecls = outerScope.getDeclaredVariables(); 3010 Set outerRefs = outerScope.getReferencedVariables(); 3011 Set innerDecls = innerScope.getDeclaredVariables(); 3012 Set innerRefs = innerScope.getReferencedVariables(); 3013 3014 mutableVars.clear(); 3015 3016 for (Iterator iter = innerDecls.iterator(); iter.hasNext();) { 3017 String var = (String ) iter.next(); 3018 if ((outerDecls.contains(var) || outerRefs.contains(var)) && classNode.getField(var) == null) { 3019 mutableVars.add(var); 3020 } 3021 } 3022 3023 for (Iterator iter = innerRefs.iterator(); iter.hasNext();) { 3026 String var = (String ) iter.next(); 3027 if (outerDecls.contains(var) && classNode.getField(var) == null) { 3028 mutableVars.add(var); 3029 } 3030 } 3031 3032 } 3040 3041 protected void addFieldsToVisitor(VariableScope scope) { 3042 for (Iterator iter = classNode.getFields().iterator(); iter.hasNext();) { 3043 FieldNode field = (FieldNode) iter.next(); 3044 String name = field.getName(); 3045 3046 scope.getDeclaredVariables().add(name); 3047 scope.getReferencedVariables().add(name); 3048 } 3049 } 3050 3051 private boolean isInnerClass() { 3052 return classNode instanceof InnerClassNode; 3053 } 3054 3055 protected String getVariableType(String name) { 3056 Variable variable = (Variable) variableStack.get(name); 3057 if (variable != null) { 3058 return variable.getTypeName(); 3059 } 3060 return null; 3061 } 3062 3063 protected void resetVariableStack(Parameter[] parameters) { 3064 lastVariableIndex = -1; 3065 variableStack.clear(); 3066 3067 scope = null; 3068 pushBlockScope(); 3069 3070 definingParameters = true; 3072 if (!isStaticMethod()) { 3073 defineVariable("this", classNode.getName()).getIndex(); 3074 } for (int i = 0; i < parameters.length; i++) { 3076 Parameter parameter = parameters[i]; 3077 String type = parameter.getType(); 3078 int idx = defineVariable(parameter.getName(), type).getIndex(); 3079 if (BytecodeHelper.isPrimitiveType(type)) { 3080 helper.load(type, idx); 3081 helper.box(type); 3082 cv.visitVarInsn(ASTORE, idx); 3083 } 3084 } 3085 definingParameters = false; 3086 } 3087 3088 protected void popScope() { 3089 int lastID = scope.getLastVariableIndex(); 3090 3091 List removeKeys = new ArrayList (); 3092 for (Iterator iter = variableStack.entrySet().iterator(); iter.hasNext();) { 3093 Map.Entry entry = (Map.Entry ) iter.next(); 3094 String name = (String ) entry.getKey(); 3095 Variable value = (Variable) entry.getValue(); 3096 if (value.getIndex() >= lastID) { 3097 removeKeys.add(name); 3098 } 3099 } 3100 for (Iterator iter = removeKeys.iterator(); iter.hasNext();) { 3101 variableStack.remove(iter.next()); 3102 } 3103 3105 scope = scope.getParent(); 3106 } 3107 3108 3109 protected void pushBlockScope() { 3110 pushBlockScope(true, true); 3111 } 3112 3113 protected void pushBlockScope(boolean canContinue, boolean canBreak) { 3114 scope = new BlockScope(scope); 3115 scope.setContinueLabel(canContinue ? new Label() : null); 3116 scope.setBreakLabel(canBreak? new Label() : null); 3117 scope.setLastVariableIndex(getNextVariableID()); 3118 } 3119 3120 3123 protected Variable defineVariable(String name, String type) { 3124 return defineVariable(name, type, true); 3125 } 3126 3127 protected Variable defineVariable(String name, String type, boolean define) { 3128 return defineVariable(name, new Type(type), define); 3129 } 3130 3131 private Variable defineVariable(String name, Type type, boolean define) { 3132 Variable answer = (Variable) variableStack.get(name); 3133 if (answer == null) { 3134 lastVariableIndex = getNextVariableID(); 3135 answer = new Variable(lastVariableIndex, type, name); 3136 if (mutableVars.contains(name)) { 3137 answer.setHolder(true); 3138 } 3139 variableStack.put(name, answer); 3140 if (define) { 3141 if (definingParameters) { 3142 if (answer.isHolder()) { 3143 cv.visitTypeInsn(NEW, "groovy/lang/Reference"); cv.visitInsn(DUP); 3145 cv.visitVarInsn(ALOAD, lastVariableIndex); 3146 cv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "(Ljava/lang/Object;)V"); cv.visitVarInsn(ASTORE, lastVariableIndex); 3148 } 3149 } 3150 else { 3151 if (answer.isHolder() && !isInScriptBody()) { 3156 cv.visitTypeInsn(NEW, "groovy/lang/Reference"); 3157 cv.visitInsn(DUP); 3158 cv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "()V"); 3159 3160 cv.visitVarInsn(ASTORE, lastVariableIndex); 3161 } 3163 else { 3164 if (!leftHandExpression) { 3165 cv.visitInsn(ACONST_NULL); 3166 cv.visitVarInsn(ASTORE, lastVariableIndex); 3167 } 3168 } 3169 } 3170 } 3171 } 3172 return answer; 3173 } 3174 3175 private int getNextVariableID() { 3176 return Math.max(lastVariableIndex + 1, variableStack.size()); 3177 } 3178 3179 3180 protected boolean isFieldOrVariable(String name) { 3181 return variableStack.containsKey(name) || classNode.getField(name) != null; 3182 } 3183 3184 protected Type checkValidType(Type type, ASTNode node, String message) { 3185 if (type.isDynamic()) { 3186 return type; 3187 } 3188 String name = checkValidType(type.getName(), node, message); 3189 if (type.getName().equals(name)) { 3190 return type; 3191 } 3192 return new Type(name); 3193 } 3194 3195 protected String checkValidType(String type, ASTNode node, String message) { 3196 if (type.endsWith("[]")) { 3197 String postfix = "[]"; 3198 String prefix = type.substring(0, type.length() - 2); 3199 return checkValidType(prefix, node, message) + postfix; 3200 } 3201 int idx = type.indexOf('$'); 3202 if (idx > 0) { 3203 String postfix = type.substring(idx); 3204 String prefix = type.substring(0, idx); 3205 return checkValidType(prefix, node, message) + postfix; 3206 } 3207 if (BytecodeHelper.isPrimitiveType(type) || "void".equals(type)) { 3208 return type; 3209 } 3210 String original = type; 3211 type = resolveClassName(type); 3212 if (type != null) { 3213 return type; 3214 } 3215 throw new MissingClassException(original, node, message + " for class: " + classNode.getName()); 3216 } 3217 3218 protected String resolveClassName(String type) { 3219 return classNode.resolveClassName(type); 3220 } 3221 3222 protected String createVariableName(String type) { 3223 return "__" + type + (++tempVariableNameCounter); 3224 } 3225 3226 3230 protected String getExpressionType(Expression expression) { 3231 if (comparisonExpression(expression)) { 3232 return "boolean"; 3233 } 3234 if (expression instanceof VariableExpression) { 3235 VariableExpression varExpr = (VariableExpression) expression; 3236 Variable variable = (Variable) variableStack.get(varExpr.getVariable()); 3237 if (variable != null && !variable.isHolder()) { 3238 Type type = variable.getType(); 3239 if (! type.isDynamic()) { 3240 return type.getName(); 3241 } 3242 } 3243 } 3244 return null; 3245 } 3246 3247 3251 protected boolean isPrimitiveFieldType(String type) { 3252 return type.equals("java.lang.String") 3253 || type.equals("java.lang.Integer") 3254 || type.equals("java.lang.Double") 3255 || type.equals("java.lang.Long") 3256 || type.equals("java.lang.Float"); 3257 } 3258 3259 protected boolean isInClosureConstructor() { 3260 return constructorNode != null 3261 && classNode.getOuterClass() != null 3262 && classNode.getSuperClass().equals(Closure.class.getName()); 3263 } 3264 3265 protected boolean isStaticMethod() { 3266 if (methodNode == null) { return false; 3268 } 3269 return methodNode.isStatic(); 3270 } 3271 3272 3275 protected Class loadClass(String name) { 3276 try { 3277 CompileUnit compileUnit = getCompileUnit(); 3278 if (compileUnit != null) { 3279 return compileUnit.loadClass(name); 3280 } 3281 else { 3282 throw new ClassGeneratorException("Could not load class: " + name); 3283 } 3284 } 3285 catch (ClassNotFoundException e) { 3286 throw new ClassGeneratorException("Could not load class: " + name + " reason: " + e, e); 3287 } 3288 } 3289 3290 protected CompileUnit getCompileUnit() { 3291 CompileUnit answer = classNode.getCompileUnit(); 3292 if (answer == null) { 3293 answer = context.getCompileUnit(); 3294 } 3295 return answer; 3296 } 3297} 3298 | Popular Tags |