1 34 package org.codehaus.groovy.classgen; 35 36 import groovy.lang.*; 37 38 import java.lang.reflect.Constructor ; 39 import java.lang.reflect.Field ; 40 import java.lang.reflect.Method ; 41 import java.lang.reflect.Modifier ; 42 import java.util.*; 43 import java.util.regex.Matcher ; 44 import java.util.logging.Logger ; 45 import java.security.AccessController ; 46 import java.security.PrivilegedAction ; 47 48 import org.codehaus.groovy.ast.ASTNode; 49 import org.codehaus.groovy.ast.ClassNode; 50 import org.codehaus.groovy.ast.CompileUnit; 51 import org.codehaus.groovy.ast.ConstructorNode; 52 import org.codehaus.groovy.ast.FieldNode; 53 import org.codehaus.groovy.ast.GroovyCodeVisitor; 54 import org.codehaus.groovy.ast.InnerClassNode; 55 import org.codehaus.groovy.ast.MethodNode; 56 import org.codehaus.groovy.ast.Parameter; 57 import org.codehaus.groovy.ast.PropertyNode; 58 import org.codehaus.groovy.ast.Type; 59 import org.codehaus.groovy.ast.VariableScope; 60 import org.codehaus.groovy.ast.expr.ArgumentListExpression; 61 import org.codehaus.groovy.ast.expr.ArrayExpression; 62 import org.codehaus.groovy.ast.expr.BinaryExpression; 63 import org.codehaus.groovy.ast.expr.BooleanExpression; 64 import org.codehaus.groovy.ast.expr.CastExpression; 65 import org.codehaus.groovy.ast.expr.ClassExpression; 66 import org.codehaus.groovy.ast.expr.ClosureExpression; 67 import org.codehaus.groovy.ast.expr.ConstantExpression; 68 import org.codehaus.groovy.ast.expr.ConstructorCallExpression; 69 import org.codehaus.groovy.ast.expr.Expression; 70 import org.codehaus.groovy.ast.expr.ExpressionTransformer; 71 import org.codehaus.groovy.ast.expr.FieldExpression; 72 import org.codehaus.groovy.ast.expr.GStringExpression; 73 import org.codehaus.groovy.ast.expr.ListExpression; 74 import org.codehaus.groovy.ast.expr.MapEntryExpression; 75 import org.codehaus.groovy.ast.expr.MapExpression; 76 import org.codehaus.groovy.ast.expr.MethodCallExpression; 77 import org.codehaus.groovy.ast.expr.NegationExpression; 78 import org.codehaus.groovy.ast.expr.NotExpression; 79 import org.codehaus.groovy.ast.expr.PostfixExpression; 80 import org.codehaus.groovy.ast.expr.PrefixExpression; 81 import org.codehaus.groovy.ast.expr.PropertyExpression; 82 import org.codehaus.groovy.ast.expr.RangeExpression; 83 import org.codehaus.groovy.ast.expr.RegexExpression; 84 import org.codehaus.groovy.ast.expr.StaticMethodCallExpression; 85 import org.codehaus.groovy.ast.expr.TernaryExpression; 86 import org.codehaus.groovy.ast.expr.TupleExpression; 87 import org.codehaus.groovy.ast.expr.VariableExpression; 88 import org.codehaus.groovy.ast.stmt.AssertStatement; 89 import org.codehaus.groovy.ast.stmt.BlockStatement; 90 import org.codehaus.groovy.ast.stmt.BreakStatement; 91 import org.codehaus.groovy.ast.stmt.CaseStatement; 92 import org.codehaus.groovy.ast.stmt.CatchStatement; 93 import org.codehaus.groovy.ast.stmt.ContinueStatement; 94 import org.codehaus.groovy.ast.stmt.DoWhileStatement; 95 import org.codehaus.groovy.ast.stmt.ExpressionStatement; 96 import org.codehaus.groovy.ast.stmt.ForStatement; 97 import org.codehaus.groovy.ast.stmt.IfStatement; 98 import org.codehaus.groovy.ast.stmt.ReturnStatement; 99 import org.codehaus.groovy.ast.stmt.Statement; 100 import org.codehaus.groovy.ast.stmt.SwitchStatement; 101 import org.codehaus.groovy.ast.stmt.SynchronizedStatement; 102 import org.codehaus.groovy.ast.stmt.ThrowStatement; 103 import org.codehaus.groovy.ast.stmt.TryCatchStatement; 104 import org.codehaus.groovy.ast.stmt.WhileStatement; 105 import org.codehaus.groovy.runtime.DefaultGroovyMethods; 106 import org.codehaus.groovy.runtime.InvokerHelper; 107 import org.codehaus.groovy.runtime.RegexSupport; 108 import org.codehaus.groovy.syntax.Token; 109 import org.codehaus.groovy.syntax.Types; 110 import org.codehaus.groovy.syntax.SyntaxException; 111 import org.codehaus.groovy.syntax.parser.RuntimeParserException; 112 import org.objectweb.asm.ClassVisitor; 113 import org.objectweb.asm.CodeVisitor; 114 import org.objectweb.asm.Label; 115 import org.objectweb.asm.ClassWriter; 116 117 125 public class AsmClassGenerator2 extends ClassGenerator { 126 127 private Logger log = Logger.getLogger(getClass().getName()); 128 129 private ClassVisitor cw; 130 private CodeVisitor cv; 131 private GeneratorContext context; 132 133 private String sourceFile; 134 135 private ClassNode classNode; 137 private ClassNode outermostClass; 138 private String internalClassName; 139 private String internalBaseClassName; 140 141 142 private Map variableStack = new HashMap(); 143 144 145 private boolean outputReturn; 146 147 148 private boolean leftHandExpression; 149 150 MethodCaller invokeMethodMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeMethod"); 152 MethodCaller invokeMethodSafeMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeMethodSafe"); 153 MethodCaller invokeStaticMethodMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeStaticMethod"); 154 MethodCaller invokeConstructorMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeConstructor"); 155 MethodCaller invokeConstructorOfMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeConstructorOf"); 156 MethodCaller invokeNoArgumentsConstructorOf = MethodCaller.newStatic(InvokerHelper.class, "invokeNoArgumentsConstructorOf"); 157 MethodCaller invokeClosureMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeClosure"); 158 MethodCaller invokeSuperMethodMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeSuperMethod"); 159 MethodCaller invokeNoArgumentsMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeNoArgumentsMethod"); 160 MethodCaller invokeStaticNoArgumentsMethod = MethodCaller.newStatic(InvokerHelper.class, "invokeStaticNoArgumentsMethod"); 161 162 MethodCaller asIntMethod = MethodCaller.newStatic(InvokerHelper.class, "asInt"); 163 MethodCaller asTypeMethod = MethodCaller.newStatic(InvokerHelper.class, "asType"); 164 MethodCaller getPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "getProperty"); 165 MethodCaller getPropertySafeMethod = MethodCaller.newStatic(InvokerHelper.class, "getPropertySafe"); 166 MethodCaller setPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "setProperty"); 167 MethodCaller setPropertyMethod2 = MethodCaller.newStatic(InvokerHelper.class, "setProperty2"); 168 MethodCaller setPropertySafeMethod2 = MethodCaller.newStatic(InvokerHelper.class, "setPropertySafe2"); 169 MethodCaller getGroovyObjectPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "getGroovyObjectProperty"); 170 MethodCaller setGroovyObjectPropertyMethod = MethodCaller.newStatic(InvokerHelper.class, "setGroovyObjectProperty"); 171 MethodCaller asIteratorMethod = MethodCaller.newStatic(InvokerHelper.class, "asIterator"); 172 MethodCaller asBool = MethodCaller.newStatic(InvokerHelper.class, "asBool"); 173 MethodCaller notBoolean = MethodCaller.newStatic(InvokerHelper.class, "notBoolean"); 174 MethodCaller notObject = MethodCaller.newStatic(InvokerHelper.class, "notObject"); 175 MethodCaller regexPattern = MethodCaller.newStatic(InvokerHelper.class, "regexPattern"); 176 MethodCaller negation = MethodCaller.newStatic(InvokerHelper.class, "negate"); 177 MethodCaller convertPrimitiveArray = MethodCaller.newStatic(InvokerHelper.class, "convertPrimitiveArray"); 178 MethodCaller convertToPrimitiveArray = MethodCaller.newStatic(InvokerHelper.class, "convertToPrimitiveArray"); 179 180 MethodCaller compareIdenticalMethod = MethodCaller.newStatic(InvokerHelper.class, "compareIdentical"); 181 MethodCaller compareEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareEqual"); 182 MethodCaller compareNotEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareNotEqual"); 183 MethodCaller compareToMethod = MethodCaller.newStatic(InvokerHelper.class, "compareTo"); 184 MethodCaller findRegexMethod = MethodCaller.newStatic(InvokerHelper.class, "findRegex"); 185 MethodCaller matchRegexMethod = MethodCaller.newStatic(InvokerHelper.class, "matchRegex"); 186 MethodCaller compareLessThanMethod = MethodCaller.newStatic(InvokerHelper.class, "compareLessThan"); 187 MethodCaller compareLessThanEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareLessThanEqual"); 188 MethodCaller compareGreaterThanMethod = MethodCaller.newStatic(InvokerHelper.class, "compareGreaterThan"); 189 MethodCaller compareGreaterThanEqualMethod = MethodCaller.newStatic(InvokerHelper.class, "compareGreaterThanEqual"); 190 MethodCaller isCaseMethod = MethodCaller.newStatic(InvokerHelper.class, "isCase"); 191 192 MethodCaller createListMethod = MethodCaller.newStatic(InvokerHelper.class, "createList"); 193 MethodCaller createTupleMethod = MethodCaller.newStatic(InvokerHelper.class, "createTuple"); 194 MethodCaller createMapMethod = MethodCaller.newStatic(InvokerHelper.class, "createMap"); 195 MethodCaller createRangeMethod = MethodCaller.newStatic(InvokerHelper.class, "createRange"); 196 197 MethodCaller assertFailedMethod = MethodCaller.newStatic(InvokerHelper.class, "assertFailed"); 198 199 MethodCaller iteratorNextMethod = MethodCaller.newInterface(Iterator.class, "next"); 200 MethodCaller iteratorHasNextMethod = MethodCaller.newInterface(Iterator.class, "hasNext"); 201 202 203 private int lastVariableIndex; 205 private static int tempVariableNameCounter; 206 207 private List exceptionBlocks = new ArrayList(); 209 210 private boolean definingParameters; 211 private Set syntheticStaticFields = new HashSet(); 212 private Set mutableVars = new HashSet(); 213 private boolean passingClosureParams; 214 215 private ConstructorNode constructorNode; 216 private MethodNode methodNode; 217 private BlockScope scope; 219 private BytecodeHelper helper = new BytecodeHelper(null); 220 221 private VariableScope variableScope; 222 public static final boolean CREATE_DEBUG_INFO = false; 223 private static final boolean MARK_START = true; 224 225 public static final String EB_SWITCH_NAME = "static.dispatching"; 226 public boolean ENABLE_EARLY_BINDING; 227 { String ebSwitch = (String ) AccessController.doPrivileged(new PrivilegedAction () { 229 public Object run() { 230 return System.getProperty(EB_SWITCH_NAME, "false"); } 232 }); 233 if (ebSwitch.equals("true")) { 235 ENABLE_EARLY_BINDING = true; 236 } 237 else if (ebSwitch.equals("false")) { 238 ENABLE_EARLY_BINDING = false; 239 } 240 else { 241 ENABLE_EARLY_BINDING = false; 242 log.warning("The value of system property " + EB_SWITCH_NAME + " is not recognized. Late dispatching is assumed. "); 243 } 244 } 245 public static final boolean ASM_DEBUG = false; private int lineNumber = -1; 247 private int columnNumber = -1; 248 private ASTNode currentASTNode = null; 249 250 private DummyClassGenerator dummyGen = null; 251 private ClassWriter dummyClassWriter = null; 252 253 public AsmClassGenerator2( 254 GeneratorContext context, 255 ClassVisitor classVisitor, 256 ClassLoader classLoader, 257 String sourceFile) { 258 super(classLoader); 259 this.context = context; 260 this.cw = classVisitor; 261 this.sourceFile = sourceFile; 262 263 this.dummyClassWriter = new ClassWriter(true); 264 dummyGen = new DummyClassGenerator(context, dummyClassWriter, classLoader, sourceFile); 265 266 } 267 268 public void visitClass(ClassNode classNode) { 271 274 try { 275 syntheticStaticFields.clear(); 276 this.classNode = classNode; 277 this.outermostClass = null; 278 this.internalClassName = BytecodeHelper.getClassInternalName(classNode.getName()); 279 280 282 classNode.setSuperClass(checkValidType(classNode.getSuperClass(), classNode, "Must be a valid base class")); 284 String [] interfaces = classNode.getInterfaces(); 285 for (int i = 0; i < interfaces.length; i++ ) { 286 interfaces[i] = checkValidType(interfaces[i], classNode, "Must be a valid interface name"); 287 } 288 289 this.internalBaseClassName = BytecodeHelper.getClassInternalName(classNode.getSuperClass()); 290 291 cw.visit( 292 asmJDKVersion, 293 classNode.getModifiers(), 294 internalClassName, 295 internalBaseClassName, 296 BytecodeHelper.getClassInternalNames(classNode.getInterfaces()), 297 sourceFile); 298 299 307 classNode.visitContents(this); 308 309 createSyntheticStaticFields(); 310 311 for (Iterator iter = innerClasses.iterator(); iter.hasNext();) { 312 ClassNode innerClass = (ClassNode) iter.next(); 313 String innerClassName = innerClass.getName(); 314 String innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassName); 315 String outerClassName = internalClassName; MethodNode enclosingMethod = innerClass.getEnclosingMethod(); 317 if (enclosingMethod != null) { 318 outerClassName = null; 320 } 321 cw.visitInnerClass( 322 innerClassInternalName, 323 outerClassName, 324 innerClassName, 325 innerClass.getModifiers()); 326 } 327 cw.visitEnd(); 329 } 330 catch (GroovyRuntimeException e) { 331 e.setModule(classNode.getModule()); 332 throw e; 333 } 334 } 335 336 private void createDummyClass(ClassNode classNode) { 340 dummyGen.visitClass(classNode); 341 byte[] code = dummyClassWriter.toByteArray(); 342 343 ClassLoader parentLoader = getClass().getClassLoader(); 344 GroovyClassLoader groovyLoader = new GroovyClassLoader(parentLoader); 345 Class theClass = groovyLoader.defineClass(classNode.getName(), code); 346 347 if (theClass != null) { 348 classCache.put(classNode.getName(), theClass); 349 } 350 } 351 352 public void visitConstructor(ConstructorNode node) { 353 356 this.constructorNode = node; 357 this.methodNode = null; 358 this.variableScope = null; 359 360 visitParameters(node, node.getParameters()); 361 362 String methodType = BytecodeHelper.getMethodDescriptor("void", node.getParameters()); 363 cv = cw.visitMethod(node.getModifiers(), "<init>", methodType, null, null); 364 helper = new BytecodeHelper(cv); 365 366 findMutableVariables(); 367 resetVariableStack(node.getParameters()); 368 369 Statement code = node.getCode(); 370 if (code == null || !firstStatementIsSuperInit(code)) { 371 cv.visitVarInsn(ALOAD, 0); 373 cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "()V"); 374 } 375 if (code != null) { 376 code.visit(this); 377 } 378 379 cv.visitInsn(RETURN); 380 cv.visitMaxs(0, 0); 381 } 382 383 public void visitMethod(MethodNode node) { 384 this.constructorNode = null; 387 this.methodNode = node; 388 this.variableScope = null; 389 390 visitParameters(node, node.getParameters()); 391 node.setReturnType(checkValidType(node.getReturnType(), node, "Must be a valid return type")); 392 393 String methodType = BytecodeHelper.getMethodDescriptor(node.getReturnType(), node.getParameters()); 394 cv = cw.visitMethod(node.getModifiers(), node.getName(), methodType, null, null); 395 Label labelStart = new Label(); 396 cv.visitLabel(labelStart); 397 helper = new BytecodeHelper(cv); 398 399 findMutableVariables(); 400 resetVariableStack(node.getParameters()); 401 402 403 outputReturn = false; 404 405 node.getCode().visit(this); 406 407 if (!outputReturn) { 408 cv.visitInsn(RETURN); 409 } 410 411 for (Iterator iter = exceptionBlocks.iterator(); iter.hasNext();) { 413 Runnable runnable = (Runnable ) iter.next(); 414 runnable.run(); 415 } 416 exceptionBlocks.clear(); 417 418 Label labelEnd = new Label(); 419 cv.visitLabel(labelEnd); 420 421 if (CREATE_DEBUG_INFO) { 423 Set vars = this.variableStack.keySet(); 424 for (Iterator iterator = vars.iterator(); iterator.hasNext();) { 425 String varName = (String ) iterator.next(); 426 Variable v = (Variable)variableStack.get(varName); 427 String type = v.getTypeName(); 428 type = BytecodeHelper.getTypeDescription(type); 429 Label start = v.getStartLabel() != null ? v.getStartLabel() : labelStart; 430 Label end = v.getEndLabel() != null ? v.getEndLabel() : labelEnd; 431 cv.visitLocalVariable(varName, type, start, end, v.getIndex()); 432 } 433 } 434 cv.visitMaxs(0, 0); 435 } 436 437 protected void visitParameters(ASTNode node, Parameter[] parameters) { 438 for (int i = 0, size = parameters.length; i < size; i++ ) { 439 visitParameter(node, parameters[i]); 440 } 441 } 442 443 protected void visitParameter(ASTNode node, Parameter parameter) { 444 if (! parameter.isDynamicType()) { 445 parameter.setType(checkValidType(parameter.getType(), node, "Must be a valid parameter class")); 446 } 447 } 448 449 public void visitField(FieldNode fieldNode) { 450 onLineNumber(fieldNode, "visitField: " + fieldNode.getName()); 451 452 fieldNode.setType(checkValidType(fieldNode.getType(), fieldNode, "Must be a valid field class for field: " + fieldNode.getName())); 454 455 458 Object fieldValue = null; 459 Expression expression = fieldNode.getInitialValueExpression(); 460 if (expression instanceof ConstantExpression) { 461 ConstantExpression constantExp = (ConstantExpression) expression; 462 Object value = constantExp.getValue(); 463 if (isPrimitiveFieldType(fieldNode.getType())) { 464 Class type = null; 466 try { 467 type = loadClass(fieldNode.getType()); 468 fieldValue = asType(value, type); 469 } 470 catch (Exception e) { 471 log.warning("Caught unexpected: " + e); 472 } 473 } 474 } 475 cw.visitField( 476 fieldNode.getModifiers(), 477 fieldNode.getName(), 478 BytecodeHelper.getTypeDescription(fieldNode.getType()), 479 null, null); 481 } 482 483 486 public void visitProperty(PropertyNode statement) { 487 onLineNumber(statement, "visitProperty:" + statement.getField().getName()); 488 this.methodNode = null; 490 } 491 492 495 498 public void visitForLoop(ForStatement loop) { 499 onLineNumber(loop, "visitForLoop"); 500 Class elemType = null; 501 if (ENABLE_EARLY_BINDING) { 502 Expression collectionExp = loop.getCollectionExpression(); 503 collectionExp.resolve(this); 504 Class cls = collectionExp.getTypeClass(); 505 if (cls != null) { 506 if (cls.isArray()) { 507 elemType = cls.getComponentType(); 508 if (elemType != null) { 509 Type varType = new Type(elemType.getName()); 510 loop.setVariableType(varType); 511 } 512 } 513 else if (collectionExp instanceof ListExpression) { 514 elemType = ((ListExpression)collectionExp).getComponentTypeClass(); 515 if (elemType != null) { 516 Type varType = new Type(elemType.getName()); 517 loop.setVariableType(varType); 518 } 519 } 520 else if (collectionExp instanceof RangeExpression) { 521 elemType = ((RangeExpression)collectionExp).getFrom().getTypeClass(); 523 if (elemType != null) { 524 Type varType = new Type(elemType.getName()); 525 loop.setVariableType(varType); 526 } 527 } 528 } 529 } 530 531 532 Type variableType = checkValidType(loop.getVariableType(), loop, "for loop variable"); 535 Variable variable = defineVariable(loop.getVariable(), variableType, true); 536 537 if( isInScriptBody() ) { 538 variable.setProperty( true ); 539 } 540 541 542 545 loop.getCollectionExpression().visit(this); 546 547 asIteratorMethod.call(cv); 548 549 final Variable iterTemp = storeInTemp("iterator", "java.util.Iterator"); 550 final int iteratorIdx = iterTemp.getIndex(); 551 552 pushBlockScope(); 555 556 Label continueLabel = scope.getContinueLabel(); 557 cv.visitJumpInsn(GOTO, continueLabel); 558 Label label2 = new Label(); 559 cv.visitLabel(label2); 560 561 final Class elemClass = elemType; 562 BytecodeExpression expression = new BytecodeExpression() { 563 public void visit(GroovyCodeVisitor visitor) { 564 cv.visitVarInsn(ALOAD, iteratorIdx); 565 iteratorNextMethod.call(cv); 566 } 567 568 protected void resolveType(AsmClassGenerator2 resolver) { 569 setTypeClass(elemClass); 570 } 571 }; 572 573 evaluateEqual( BinaryExpression.newAssignmentExpression(loop.getVariable(), expression) ); 574 cv.visitInsn(POP); 576 579 loop.getLoopBlock().visit(this); 580 581 582 585 cv.visitLabel(continueLabel); 586 cv.visitVarInsn(ALOAD, iteratorIdx); 587 588 iteratorHasNextMethod.call(cv); 589 590 cv.visitJumpInsn(IFNE, label2); 591 592 cv.visitLabel(scope.getBreakLabel()); 593 popScope(); 594 } 595 596 public void visitWhileLoop(WhileStatement loop) { 597 onLineNumber(loop, "visitWhileLoop"); 598 599 pushBlockScope(); 600 601 Label continueLabel = scope.getContinueLabel(); 602 603 cv.visitJumpInsn(GOTO, continueLabel); 604 Label l1 = new Label(); 605 cv.visitLabel(l1); 606 607 loop.getLoopBlock().visit(this); 608 609 cv.visitLabel(continueLabel); 610 611 loop.getBooleanExpression().visit(this); 612 613 cv.visitJumpInsn(IFNE, l1); 614 615 cv.visitLabel(scope.getBreakLabel()); 616 popScope(); 617 } 618 619 public void visitDoWhileLoop(DoWhileStatement loop) { 620 onLineNumber(loop, "visitDoWhileLoop"); 621 622 pushBlockScope(); 623 624 Label breakLabel = scope.getBreakLabel(); 625 626 Label continueLabel = scope.getContinueLabel(); 627 cv.visitLabel(continueLabel); 628 Label l1 = new Label(); 629 630 loop.getLoopBlock().visit(this); 631 632 cv.visitLabel(l1); 633 634 loop.getBooleanExpression().visit(this); 635 636 cv.visitJumpInsn(IFNE, continueLabel); 637 638 cv.visitLabel(breakLabel); 639 popScope(); 640 } 641 642 public void visitIfElse(IfStatement ifElse) { 643 onLineNumber(ifElse, "visitIfElse"); 644 645 ifElse.getBooleanExpression().visit(this); 646 647 Label l0 = new Label(); 648 cv.visitJumpInsn(IFEQ, l0); 649 pushBlockScope(false, false); 650 ifElse.getIfBlock().visit(this); 651 popScope(); 652 653 Label l1 = new Label(); 654 cv.visitJumpInsn(GOTO, l1); 655 cv.visitLabel(l0); 656 657 pushBlockScope(false, false); 658 ifElse.getElseBlock().visit(this); 659 cv.visitLabel(l1); 660 popScope(); 661 } 662 663 public void visitTernaryExpression(TernaryExpression expression) { 664 onLineNumber(expression, "visitTernaryExpression"); 665 666 expression.getBooleanExpression().visit(this); 667 668 Label l0 = new Label(); 669 cv.visitJumpInsn(IFEQ, l0); 670 expression.getTrueExpression().visit(this); 671 672 Label l1 = new Label(); 673 cv.visitJumpInsn(GOTO, l1); 674 cv.visitLabel(l0); 675 676 expression.getFalseExpression().visit(this); 677 cv.visitLabel(l1); 678 } 679 680 public void visitAssertStatement(AssertStatement statement) { 681 onLineNumber(statement, "visitAssertStatement"); 682 683 686 BooleanExpression booleanExpression = statement.getBooleanExpression(); 687 booleanExpression.visit(this); 688 689 Label l0 = new Label(); 690 cv.visitJumpInsn(IFEQ, l0); 691 692 694 Label l1 = new Label(); 695 cv.visitJumpInsn(GOTO, l1); 696 cv.visitLabel(l0); 697 698 String expressionText = booleanExpression.getText(); 700 List list = new ArrayList(); 701 addVariableNames(booleanExpression, list); 702 if (list.isEmpty()) { 703 cv.visitLdcInsn(expressionText); 704 } 705 else { 706 boolean first = true; 707 708 cv.visitTypeInsn(NEW, "java/lang/StringBuffer"); 710 cv.visitInsn(DUP); 711 cv.visitLdcInsn(expressionText + ". Values: "); 712 713 cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "(Ljava/lang/String;)V"); 714 715 Variable assertTemp = visitASTOREInTemp("assert"); 716 int tempIndex = assertTemp.getIndex(); 717 718 for (Iterator iter = list.iterator(); iter.hasNext();) { 719 String name = (String ) iter.next(); 720 String text = name + " = "; 721 if (first) { 722 first = false; 723 } 724 else { 725 text = ", " + text; 726 } 727 728 cv.visitVarInsn(ALOAD, tempIndex); 729 cv.visitLdcInsn(text); 730 cv.visitMethodInsn( 731 INVOKEVIRTUAL, 732 "java/lang/StringBuffer", 733 "append", 734 "(Ljava/lang/Object;)Ljava/lang/StringBuffer;"); 735 cv.visitInsn(POP); 736 737 cv.visitVarInsn(ALOAD, tempIndex); 738 new VariableExpression(name).visit(this); 739 cv.visitMethodInsn( 740 INVOKEVIRTUAL, 741 "java/lang/StringBuffer", 742 "append", 743 "(Ljava/lang/Object;)Ljava/lang/StringBuffer;"); 744 cv.visitInsn(POP); 745 746 } 747 cv.visitVarInsn(ALOAD, tempIndex); 748 removeVar(assertTemp); 749 } 750 statement.getMessageExpression().visit(this); 752 753 assertFailedMethod.call(cv); 754 cv.visitLabel(l1); 755 } 756 757 private void addVariableNames(Expression expression, List list) { 758 if (expression instanceof BooleanExpression) { 759 BooleanExpression boolExp = (BooleanExpression) expression; 760 addVariableNames(boolExp.getExpression(), list); 761 } 762 else if (expression instanceof BinaryExpression) { 763 BinaryExpression binExp = (BinaryExpression) expression; 764 addVariableNames(binExp.getLeftExpression(), list); 765 addVariableNames(binExp.getRightExpression(), list); 766 } 767 else if (expression instanceof VariableExpression) { 768 VariableExpression varExp = (VariableExpression) expression; 769 list.add(varExp.getVariable()); 770 } 771 } 772 773 public void visitTryCatchFinally(TryCatchStatement statement) { 774 onLineNumber(statement, "visitTryCatchFinally"); 775 CatchStatement catchStatement = statement.getCatchStatement(0); 777 778 Statement tryStatement = statement.getTryStatement(); 779 780 if (tryStatement.isEmpty() || catchStatement == null) { 781 final Label l0 = new Label(); 782 cv.visitLabel(l0); 783 784 tryStatement.visit(this); 785 786 787 int index1 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex(); 788 int index2 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex(); 789 790 final Label l1 = new Label(); 791 cv.visitJumpInsn(JSR, l1); 792 final Label l2 = new Label(); 793 cv.visitLabel(l2); 794 final Label l3 = new Label(); 795 cv.visitJumpInsn(GOTO, l3); 796 final Label l4 = new Label(); 797 cv.visitLabel(l4); 798 cv.visitVarInsn(ASTORE, index1); 799 cv.visitJumpInsn(JSR, l1); 800 final Label l5 = new Label(); 801 cv.visitLabel(l5); 802 cv.visitVarInsn(ALOAD, index1); 803 cv.visitInsn(ATHROW); 804 cv.visitLabel(l1); 805 cv.visitVarInsn(ASTORE, index2); 806 807 statement.getFinallyStatement().visit(this); 808 809 cv.visitVarInsn(RET, index2); 810 cv.visitLabel(l3); 811 812 exceptionBlocks.add(new Runnable () { 813 public void run() { 814 cv.visitTryCatchBlock(l0, l2, l4, null); 815 cv.visitTryCatchBlock(l4, l5, l4, null); 816 } 817 }); 818 819 } 820 else { 821 String exceptionVar = catchStatement.getVariable(); 822 String exceptionType = 823 checkValidType(catchStatement.getExceptionType(), catchStatement, "in catch statement"); 824 825 int exceptionIndex = defineVariable(exceptionVar, exceptionType, false).getIndex(); 826 int index2 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex(); 827 int index3 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex(); 828 829 final Label l0 = new Label(); 830 cv.visitLabel(l0); 831 832 tryStatement.visit(this); 833 834 final Label l1 = new Label(); 835 cv.visitLabel(l1); 836 Label l2 = new Label(); 837 cv.visitJumpInsn(JSR, l2); 838 final Label l3 = new Label(); 839 cv.visitLabel(l3); 840 Label l4 = new Label(); 841 cv.visitJumpInsn(GOTO, l4); 842 final Label l5 = new Label(); 843 cv.visitLabel(l5); 844 845 cv.visitVarInsn(ASTORE, exceptionIndex); 846 847 if (catchStatement != null) { 848 catchStatement.visit(this); 849 } 850 851 cv.visitJumpInsn(JSR, l2); 852 final Label l6 = new Label(); 853 cv.visitLabel(l6); 854 cv.visitJumpInsn(GOTO, l4); 855 856 final Label l7 = new Label(); 857 cv.visitLabel(l7); 858 cv.visitVarInsn(ASTORE, index2); 859 cv.visitJumpInsn(JSR, l2); 860 861 final Label l8 = new Label(); 862 cv.visitLabel(l8); 863 cv.visitVarInsn(ALOAD, index2); 864 cv.visitInsn(ATHROW); 865 cv.visitLabel(l2); 866 cv.visitVarInsn(ASTORE, index3); 867 868 statement.getFinallyStatement().visit(this); 869 870 cv.visitVarInsn(RET, index3); 871 cv.visitLabel(l4); 872 873 875 final String exceptionTypeInternalName = 879 (catchStatement != null) ? BytecodeHelper.getClassInternalName(exceptionType) : null; 880 881 exceptionBlocks.add(new Runnable () { 882 public void run() { 883 cv.visitTryCatchBlock(l0, l1, l5, exceptionTypeInternalName); 884 cv.visitTryCatchBlock(l0, l3, l7, null); 885 cv.visitTryCatchBlock(l5, l6, l7, null); 886 cv.visitTryCatchBlock(l7, l8, l7, null); 887 } 888 }); 889 } 890 } 891 892 private Variable storeInTemp(String name, String type) { 893 Variable var = defineVariable(createVariableName(name), type, false); 894 int varIdx = var.getIndex(); 895 cv.visitVarInsn(ASTORE, varIdx); 896 if (CREATE_DEBUG_INFO) cv.visitLabel(var.getStartLabel()); 897 return var; 898 } 899 900 public void visitSwitch(SwitchStatement statement) { 901 onLineNumber(statement, "visitSwitch"); 902 903 statement.getExpression().visit(this); 904 905 pushBlockScope(false, true); 907 909 910 int switchVariableIndex = defineVariable(createVariableName("switch"), "java.lang.Object").getIndex(); 911 cv.visitVarInsn(ASTORE, switchVariableIndex); 912 913 List caseStatements = statement.getCaseStatements(); 914 int caseCount = caseStatements.size(); 915 Label[] labels = new Label[caseCount + 1]; 916 for (int i = 0; i < caseCount; i++) { 917 labels[i] = new Label(); 918 } 919 920 int i = 0; 921 for (Iterator iter = caseStatements.iterator(); iter.hasNext(); i++) { 922 CaseStatement caseStatement = (CaseStatement) iter.next(); 923 visitCaseStatement(caseStatement, switchVariableIndex, labels[i], labels[i + 1]); 924 } 925 926 statement.getDefaultStatement().visit(this); 927 928 cv.visitLabel(scope.getBreakLabel()); 929 930 popScope(); 931 } 932 933 public void visitCaseStatement(CaseStatement statement) { 934 } 935 936 public void visitCaseStatement( 937 CaseStatement statement, 938 int switchVariableIndex, 939 Label thisLabel, 940 Label nextLabel) { 941 942 onLineNumber(statement, "visitCaseStatement"); 943 944 cv.visitVarInsn(ALOAD, switchVariableIndex); 945 statement.getExpression().visit(this); 946 947 isCaseMethod.call(cv); 948 949 Label l0 = new Label(); 950 cv.visitJumpInsn(IFEQ, l0); 951 952 cv.visitLabel(thisLabel); 953 954 statement.getCode().visit(this); 955 956 if (nextLabel != null) { 959 cv.visitJumpInsn(GOTO, nextLabel); 960 } 961 962 cv.visitLabel(l0); 963 } 964 965 public void visitBreakStatement(BreakStatement statement) { 966 onLineNumber(statement, "visitBreakStatement"); 967 968 Label breakLabel = scope.getBreakLabel(); 969 if (breakLabel != null ) { 970 cv.visitJumpInsn(GOTO, breakLabel); 971 } else { 972 } 974 } 975 976 public void visitContinueStatement(ContinueStatement statement) { 977 onLineNumber(statement, "visitContinueStatement"); 978 979 Label continueLabel = scope.getContinueLabel(); 980 if (continueLabel != null ) { 981 cv.visitJumpInsn(GOTO, continueLabel); 982 } else { 983 } 985 } 986 987 public void visitSynchronizedStatement(SynchronizedStatement statement) { 988 onLineNumber(statement, "visitSynchronizedStatement"); 989 990 statement.getExpression().visit(this); 991 992 int index = defineVariable(createVariableName("synchronized"), "java.lang.Integer").getIndex(); 993 994 cv.visitVarInsn(ASTORE, index); 995 cv.visitInsn(MONITORENTER); 996 final Label l0 = new Label(); 997 cv.visitLabel(l0); 998 999 statement.getCode().visit(this); 1000 1001 cv.visitVarInsn(ALOAD, index); 1002 cv.visitInsn(MONITOREXIT); 1003 final Label l1 = new Label(); 1004 cv.visitJumpInsn(GOTO, l1); 1005 final Label l2 = new Label(); 1006 cv.visitLabel(l2); 1007 cv.visitVarInsn(ALOAD, index); 1008 cv.visitInsn(MONITOREXIT); 1009 cv.visitInsn(ATHROW); 1010 cv.visitLabel(l1); 1011 1012 exceptionBlocks.add(new Runnable () { 1013 public void run() { 1014 cv.visitTryCatchBlock(l0, l2, l2, null); 1015 } 1016 }); 1017 } 1018 1019 public void visitThrowStatement(ThrowStatement statement) { 1020 statement.getExpression().visit(this); 1021 1022 cv.visitTypeInsn(CHECKCAST, "java/lang/Throwable"); 1024 1025 cv.visitInsn(ATHROW); 1026 } 1027 1028 public void visitReturnStatement(ReturnStatement statement) { 1029 onLineNumber(statement, "visitReturnStatement"); 1030 String returnType = methodNode.getReturnType(); 1031 if (returnType.equals("void")) { 1032 if (!(statement == ReturnStatement.RETURN_NULL_OR_VOID)) { 1033 throwException("Cannot use return statement with an expression on a method that returns void"); 1034 } 1035 cv.visitInsn(RETURN); 1036 outputReturn = true; 1037 return; 1038 } 1039 1040 Expression expression = statement.getExpression(); 1041 evaluateExpression(expression); 1042 if (returnType.equals("java.lang.Object") && expression.getType() != null && expression.getType().equals("void")) { 1043 cv.visitInsn(ACONST_NULL); cv.visitInsn(ARETURN); 1045 } else { 1046 helper.unbox(returnType); 1050 if (returnType.equals("double")) { 1051 cv.visitInsn(DRETURN); 1052 } 1053 else if (returnType.equals("float")) { 1054 cv.visitInsn(FRETURN); 1055 } 1056 else if (returnType.equals("long")) { 1057 cv.visitInsn(LRETURN); 1058 } 1059 else if (returnType.equals("boolean")) { 1060 cv.visitInsn(IRETURN); 1061 } 1062 else if ( 1063 returnType.equals("char") 1064 || returnType.equals("byte") 1065 || returnType.equals("int") 1066 || returnType.equals("short")) { cv.visitInsn(IRETURN); 1069 } 1070 else { 1071 doConvertAndCast(returnType, expression); 1072 cv.visitInsn(ARETURN); 1073 1074 1091 } 1092 } 1093 outputReturn = true; 1094 } 1095 1096 1099 protected void doConvertAndCast(String type, Expression expression) { 1100 String expType = getExpressionType(expression); 1101 if (BytecodeHelper.isPrimitiveType(type)) { 1103 type = BytecodeHelper.getObjectTypeForPrimitive(type); 1104 } 1105 if (isValidTypeForCast(type) && (expType == null || !type.equals(expType))) { 1106 doConvertAndCast(type); 1107 } 1108 } 1109 1110 1113 protected void evaluateExpression(Expression expression) { 1114 visitAndAutoboxBoolean(expression); 1115 1117 Expression assignExpr = createReturnLHSExpression(expression); 1118 if (assignExpr != null) { 1119 leftHandExpression = false; 1120 assignExpr.visit(this); 1121 } 1122 } 1123 1124 public void visitExpressionStatement(ExpressionStatement statement) { 1125 onLineNumber(statement, "visitExpressionStatement: " + statement.getExpression().getClass().getName()); 1126 1127 Expression expression = statement.getExpression(); 1128 1132 visitAndAutoboxBoolean(expression); 1133 1134 if (isPopRequired(expression)) { 1135 cv.visitInsn(POP); 1136 } 1137 } 1138 1139 1142 public void visitBinaryExpression(BinaryExpression expression) { 1143 onLineNumber(expression, "visitBinaryExpression: \"" + expression.getOperation().getText() + "\" "); 1144 switch (expression.getOperation().getType()) { 1145 case Types.EQUAL : evaluateEqual(expression); 1147 break; 1148 1149 case Types.COMPARE_IDENTICAL : evaluateBinaryExpression(compareIdenticalMethod, expression); 1151 break; 1152 1153 case Types.COMPARE_EQUAL : evaluateBinaryExpression(compareEqualMethod, expression); 1155 break; 1156 1157 case Types.COMPARE_NOT_EQUAL : 1158 evaluateBinaryExpression(compareNotEqualMethod, expression); 1159 break; 1160 1161 case Types.COMPARE_TO : 1162 evaluateCompareTo(expression); 1163 break; 1164 1165 case Types.COMPARE_GREATER_THAN : 1166 evaluateBinaryExpression(compareGreaterThanMethod, expression); 1167 break; 1168 1169 case Types.COMPARE_GREATER_THAN_EQUAL : 1170 evaluateBinaryExpression(compareGreaterThanEqualMethod, expression); 1171 break; 1172 1173 case Types.COMPARE_LESS_THAN : 1174 evaluateBinaryExpression(compareLessThanMethod, expression); 1175 break; 1176 1177 case Types.COMPARE_LESS_THAN_EQUAL : 1178 evaluateBinaryExpression(compareLessThanEqualMethod, expression); 1179 break; 1180 1181 case Types.LOGICAL_AND : 1182 evaluateLogicalAndExpression(expression); 1183 break; 1184 1185 case Types.LOGICAL_OR : 1186 evaluateLogicalOrExpression(expression); 1187 break; 1188 1189 case Types.PLUS : 1190 { 1191 if (ENABLE_EARLY_BINDING) { 1192 expression.resolve(this); 1193 if (expression.isResolveFailed() || !expression.isTypeResolved()) { 1194 evaluateBinaryExpression("plus", expression); 1195 break; 1196 } 1197 Expression leftExpression = expression.getLeftExpression(); 1198 Expression rightExpression = expression.getRightExpression(); 1199 Class lclass = leftExpression.getTypeClass(); 1200 Class rclass = rightExpression.getTypeClass(); 1201 if (lclass == null || rclass == null) { 1202 evaluateBinaryExpression("plus", expression); 1203 break; 1204 } 1205 if (lclass == String .class && rclass == String .class) { 1206 cv.visitTypeInsn(NEW, "java/lang/StringBuffer"); 1213 cv.visitInsn(DUP); 1214 cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "()V"); 1215 load(leftExpression); 1216 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;"); 1217 load(rightExpression); 1218 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;"); 1219 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "toString", "()Ljava/lang/String;"); 1220 } 1221 else if (lclass == String .class && Number .class.isAssignableFrom(rclass) ) { 1222 cv.visitTypeInsn(NEW, "java/lang/StringBuffer"); 1223 cv.visitInsn(DUP); 1224 cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "()V"); 1225 load(leftExpression); 1226 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;"); 1227 load(rightExpression); 1228 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;"); 1230 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;"); 1231 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "toString", "()Ljava/lang/String;"); 1232 } 1233 else if (rclass == String .class && Number .class.isAssignableFrom(lclass) ) { 1234 cv.visitTypeInsn(NEW, "java/lang/StringBuffer"); 1235 cv.visitInsn(DUP); 1236 cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "()V"); 1237 load(leftExpression); 1238 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;"); 1239 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 1240 load(rightExpression); 1241 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;"); cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "toString", "()Ljava/lang/String;"); 1243 } 1244 else if ((lclass == Integer .class || lclass == int.class) && (rclass == Integer .class || rclass == int.class)) { 1245 load(leftExpression); 1247 helper.quickUnboxIfNecessary(int.class); 1248 load(rightExpression); 1249 helper.quickUnboxIfNecessary(int.class); 1250 cv.visitInsn(IADD); 1251 helper.quickBoxIfNecessary(int.class); 1252 } 1253 else if (Number .class.isAssignableFrom(lclass) && Number .class.isAssignableFrom(rclass)) { 1254 load(leftExpression); 1256 load(rightExpression); 1257 cv.visitMethodInsn( 1258 INVOKESTATIC, 1259 BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()), 1260 "plus", 1261 "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;"); 1262 } 1263 else { evaluateBinaryExpression("plus", expression); 1265 } 1266 1267 } else { 1268 evaluateBinaryExpression("plus", expression); 1269 } 1270 } 1271 break; 1272 1273 case Types.PLUS_EQUAL : 1274 evaluateBinaryExpressionWithAsignment("plus", expression); 1275 break; 1276 case Types.MINUS : 1277 { 1278 if (ENABLE_EARLY_BINDING) { 1279 expression.resolve(this); 1280 if (expression.isResolveFailed() || !expression.isTypeResolved()) { 1281 evaluateBinaryExpression("minus", expression); 1282 break; 1283 } 1284 Expression leftExpression = expression.getLeftExpression(); 1285 Expression rightExpression = expression.getRightExpression(); 1286 Class lclass = leftExpression.getTypeClass(); 1287 Class rclass = rightExpression.getTypeClass(); 1288 if (lclass == null || rclass == null) { 1289 evaluateBinaryExpression("minus", expression); 1290 break; 1291 } 1292 if ((lclass == Integer .class || lclass == int.class) && (rclass == Integer .class || rclass == int.class)) { 1293 load(leftExpression); 1295 helper.quickUnboxIfNecessary(int.class); 1296 load(rightExpression); 1297 helper.quickUnboxIfNecessary(int.class); 1298 cv.visitInsn(ISUB); 1299 helper.quickBoxIfNecessary(int.class); 1300 } 1301 else 1302 if (Number .class.isAssignableFrom(lclass) && Number .class.isAssignableFrom(rclass)) { 1303 load(leftExpression); 1305 load(rightExpression); 1306 cv.visitMethodInsn( 1307 INVOKESTATIC, 1308 BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()), 1309 "minus", 1310 "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;"); 1311 } 1312 else { evaluateBinaryExpression("minus", expression); 1314 } 1315 } else { 1316 evaluateBinaryExpression("minus", expression); 1317 } 1318 } 1319 break; 1320 case Types.MINUS_EQUAL : 1321 evaluateBinaryExpressionWithAsignment("minus", expression); 1322 break; 1323 1324 case Types.MULTIPLY : 1325 { 1326 if (ENABLE_EARLY_BINDING) { 1327 expression.resolve(this); 1328 if (expression.isResolveFailed() || !expression.isTypeResolved()) { 1329 evaluateBinaryExpression("multiply", expression); 1330 break; 1331 } 1332 Expression leftExpression = expression.getLeftExpression(); 1333 Expression rightExpression = expression.getRightExpression(); 1334 Class lclass = leftExpression.getTypeClass(); 1335 Class rclass = rightExpression.getTypeClass(); 1336 if (lclass == null || rclass == null) { 1337 evaluateBinaryExpression("multiply", expression); 1338 break; 1339 } 1340 if ((lclass == Integer .class || lclass == int.class) && (rclass == Integer .class || rclass == int.class)) { 1341 load(leftExpression); 1343 helper.quickUnboxIfNecessary(int.class); 1344 load(rightExpression); 1345 helper.quickUnboxIfNecessary(int.class); 1346 cv.visitInsn(IMUL); 1347 helper.quickBoxIfNecessary(int.class); 1348 } 1349 else if (Number .class.isAssignableFrom(lclass) && Number .class.isAssignableFrom(rclass)) { 1350 load(leftExpression); 1352 load(rightExpression); 1353 cv.visitMethodInsn( 1354 INVOKESTATIC, 1355 BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()), 1356 "multiply", 1357 "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;"); 1358 } 1359 else { evaluateBinaryExpression("multiply", expression); 1361 } 1362 } else { 1363 evaluateBinaryExpression("multiply", expression); 1364 } 1365 } 1366 1367 break; 1368 1369 case Types.MULTIPLY_EQUAL : 1370 evaluateBinaryExpressionWithAsignment("multiply", expression); 1371 break; 1372 1373 case Types.DIVIDE : 1374 { 1377 if (ENABLE_EARLY_BINDING) { 1378 expression.resolve(this); 1379 if (expression.isResolveFailed() || !expression.isTypeResolved()) { 1380 evaluateBinaryExpression("div", expression); 1381 break; 1382 } 1383 Expression leftExpression = expression.getLeftExpression(); 1384 Expression rightExpression = expression.getRightExpression(); 1385 Class lclass = leftExpression.getTypeClass(); 1386 Class rclass = rightExpression.getTypeClass(); 1387 if (lclass == null || rclass == null) { 1388 evaluateBinaryExpression("div", expression); 1389 break; 1390 } 1391 if (Number .class.isAssignableFrom(lclass) && Number .class.isAssignableFrom(rclass)) { 1405 load(leftExpression); 1407 load(rightExpression); 1408 cv.visitMethodInsn( 1409 INVOKESTATIC, 1410 BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()), 1411 "div", 1412 "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;"); 1413 } 1414 else { evaluateBinaryExpression("div", expression); 1416 } 1417 } else { 1418 evaluateBinaryExpression("div", expression); 1419 } 1420 } 1421 1422 break; 1423 1424 case Types.DIVIDE_EQUAL : 1425 evaluateBinaryExpressionWithAsignment("div", expression); 1428 break; 1429 1430 case Types.INTDIV : 1431 { 1432 if (ENABLE_EARLY_BINDING) { 1433 expression.resolve(this); 1434 if (expression.isResolveFailed() || !expression.isTypeResolved()) { 1435 evaluateBinaryExpression("intdiv", expression); 1436 break; 1437 } 1438 Expression leftExpression = expression.getLeftExpression(); 1439 Expression rightExpression = expression.getRightExpression(); 1440 Class lclass = leftExpression.getTypeClass(); 1441 Class rclass = rightExpression.getTypeClass(); 1442 if (lclass == null || rclass == null) { 1443 evaluateBinaryExpression("intdiv", expression); 1444 break; 1445 } 1446 if (Number .class.isAssignableFrom(lclass) && Number .class.isAssignableFrom(rclass)) { 1447 load(leftExpression); 1449 load(rightExpression); 1450 cv.visitMethodInsn( 1451 INVOKESTATIC, 1452 BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()), 1453 "intdiv", 1454 "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;"); 1455 } 1456 else { evaluateBinaryExpression("intdiv", expression); 1458 } 1459 } else { 1460 evaluateBinaryExpression("intdiv", expression); 1461 } 1462 } 1463 break; 1464 1465 case Types.INTDIV_EQUAL : 1466 evaluateBinaryExpressionWithAsignment("intdiv", expression); 1467 break; 1468 1469 case Types.MOD : 1470 evaluateBinaryExpression("mod", expression); 1471 break; 1472 1473 case Types.MOD_EQUAL : 1474 evaluateBinaryExpressionWithAsignment("mod", expression); 1475 break; 1476 1477 case Types.LEFT_SHIFT : 1478 evaluateBinaryExpression("leftShift", expression); 1479 break; 1480 1481 case Types.RIGHT_SHIFT : 1482 evaluateBinaryExpression("rightShift", expression); 1483 break; 1484 1485 case Types.RIGHT_SHIFT_UNSIGNED : 1486 evaluateBinaryExpression("rightShiftUnsigned", expression); 1487 break; 1488 1489 case Types.KEYWORD_INSTANCEOF : 1490 evaluateInstanceof(expression); 1491 break; 1492 1493 case Types.FIND_REGEX : 1494 evaluateBinaryExpression(findRegexMethod, expression); 1495 break; 1496 1497 case Types.MATCH_REGEX : 1498 evaluateBinaryExpression(matchRegexMethod, expression); 1499 break; 1500 1501 case Types.LEFT_SQUARE_BRACKET : 1502 if (leftHandExpression) { 1503 throwException("Should not be called here. Possible reason: postfix operation on array."); 1504 } 1508 else if (ENABLE_EARLY_BINDING) { 1509 expression.resolve(this); 1510 if (expression.isResolveFailed() || !expression.isTypeResolved()) { 1511 evaluateBinaryExpression("getAt", expression); 1512 break; 1513 } 1514 Expression leftExpression = expression.getLeftExpression(); 1515 Expression rightExpression = expression.getRightExpression(); 1516 Class lclass = leftExpression.getTypeClass(); 1517 Class rclass = rightExpression.getTypeClass(); 1518 if (lclass == null || rclass == null) { 1519 evaluateBinaryExpression("getAt", expression); 1520 break; 1521 } 1522 if (lclass == String .class && rclass == Integer .class) { 1523 load(leftExpression); cast(String .class); 1524 load(rightExpression); helper.quickUnboxIfNecessary(int.class); 1525 cv.visitMethodInsn( 1526 INVOKESTATIC, 1527 BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()), 1528 "getAt", 1529 "([Ljava/lang/String;I)Ljava/lang/String;"); 1530 break; 1531 } 1532 else if (lclass.isArray() && rclass == Integer .class) { 1533 load(leftExpression); load(rightExpression); helper.quickUnboxIfNecessary(int.class); 1535 Class elemType = lclass.getComponentType(); 1536 if (!elemType.isPrimitive()) { 1537 cv.visitMethodInsn( 1538 INVOKESTATIC, 1539 BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()), 1540 "getAt", 1541 "([Ljava/lang/Object;I)Ljava/lang/Object;"); 1542 cast(elemType); 1543 } 1544 else { 1545 evaluateBinaryExpression("getAt", expression); } 1547 break; 1548 } 1549 else if (List.class == lclass && rclass == Integer .class){ 1550 load(leftExpression); cast(List.class); 1552 load(rightExpression); helper.quickUnboxIfNecessary(int.class); 1553 cv.visitMethodInsn( 1555 INVOKESTATIC, 1556 BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()), 1557 "getAt", 1558 "(Ljava/util/List;I)Ljava/lang/Object;"); 1559 break; 1560 } 1561 else if (Map.class.isAssignableFrom(lclass)){ visitMethodCallExpression( 1563 new MethodCallExpression( 1564 leftExpression, 1565 "get", 1566 new ArgumentListExpression( 1567 new Expression[] { rightExpression}))); 1568 break; 1569 } 1570 else { 1571 evaluateBinaryExpression("getAt", expression); break; 1573 } 1574 } 1575 else { 1576 evaluateBinaryExpression("getAt", expression); 1577 } 1578 break; 1579 1580 default : 1581 throwException("Operation: " + expression.getOperation() + " not supported"); 1582 } 1583 } 1584 1585 private void load(Expression exp) { 1586 1587 boolean wasLeft = leftHandExpression; 1588 leftHandExpression = false; 1589 visitAndAutoboxBoolean(exp); 1594 1597 1598 if (ENABLE_EARLY_BINDING){ 1599 1601 } 1606 leftHandExpression = wasLeft; 1608 } 1609 1610 public void visitPostfixExpression(PostfixExpression expression) { 1611 if (ENABLE_EARLY_BINDING) { 1612 int type = expression.getOperation().getType(); 1613 expression.resolve(this); 1614 if (expression.isResolveFailed() || !expression.isTypeResolved()) { 1615 evaluatePostfixMethod("next", expression.getExpression()); 1616 return; 1617 } 1618 Class lclass = expression.getTypeClass(); 1619 Expression exp = expression.getExpression(); 1620 String func = type == Types.PLUS_PLUS ? "next" : "previous"; 1621 int op = type == Types.PLUS_PLUS ? IADD : ISUB; 1622 1623 if (lclass == Integer .class) { 1624 load(exp); 1625 cv.visitInsn(DUP); helper.quickUnboxIfNecessary(int.class); 1627 cv.visitInsn(ICONST_1); 1628 cv.visitInsn(op); 1629 helper.quickBoxIfNecessary(int.class); 1630 store(exp); 1631 } 1632 else if (Number .class.isAssignableFrom(lclass)) { 1633 load(exp); 1635 cv.visitInsn(DUP); cv.visitMethodInsn( 1637 INVOKESTATIC, 1638 BytecodeHelper.getClassInternalName(DefaultGroovyMethods.class.getName()), 1639 func, 1640 "(Ljava/lang/Number;)Ljava/lang/Number;"); 1641 store(exp); 1642 } 1643 else { evaluatePostfixMethod(func, exp); 1645 } 1646 1647 } else { 1648 switch (expression.getOperation().getType()) { 1649 case Types.PLUS_PLUS : 1650 evaluatePostfixMethod("next", expression.getExpression()); 1651 break; 1652 case Types.MINUS_MINUS : 1653 evaluatePostfixMethod("previous", expression.getExpression()); 1654 break; 1655 } 1656 } 1657 } 1658 1659 private void store(Expression expression) { 1661 if (expression instanceof BinaryExpression) { 1662 throwException("BinaryExpression appeared on LHS. "); 1663 } 1664 if (ASM_DEBUG) { 1665 if (expression instanceof VariableExpression) { 1666 helper.mark(((VariableExpression)expression).getVariable()); 1667 } 1668 } 1669 boolean wasLeft = leftHandExpression; 1670 leftHandExpression = true; 1671 expression.visit(this); 1672 leftHandExpression = wasLeft; 1674 return; 1675 } 1676 1677 private void throwException(String s) { 1678 throw new RuntimeParserException(s, currentASTNode); 1680 } 1681 1682 public void visitPrefixExpression(PrefixExpression expression) { 1683 switch (expression.getOperation().getType()) { 1684 case Types.PLUS_PLUS : 1685 evaluatePrefixMethod("next", expression.getExpression()); 1686 break; 1687 case Types.MINUS_MINUS : 1688 evaluatePrefixMethod("previous", expression.getExpression()); 1689 break; 1690 } 1691 } 1692 1693 public void visitClosureExpression(ClosureExpression expression) { 1694 ClassNode innerClass = createClosureClass(expression); 1695 addInnerClass(innerClass); 1696 String innerClassinternalName = BytecodeHelper.getClassInternalName(innerClass.getName()); 1697 1698 ClassNode owner = innerClass.getOuterClass(); 1699 String ownerTypeName = owner.getName(); 1700 if (classNode.isStaticClass() || isStaticMethod()) { 1701 ownerTypeName = "java.lang.Class"; 1702 } 1703 1704 passingClosureParams = true; 1705 List constructors = innerClass.getDeclaredConstructors(); 1706 ConstructorNode node = (ConstructorNode) constructors.get(0); 1707 Parameter[] localVariableParams = node.getParameters(); 1708 1709 1710 1716 for (int i = 2; i < localVariableParams.length; i++) { 1717 Parameter param = localVariableParams[i]; 1718 String name = param.getName(); 1719 1720 if (variableStack.get(name) == null && classNode.getField(name) == null) { 1721 defineVariable(name, "java.lang.Object"); } 1723 } 1724 1725 cv.visitTypeInsn(NEW, innerClassinternalName); 1726 cv.visitInsn(DUP); 1727 if (isStaticMethod() || classNode.isStaticClass()) { 1728 visitClassExpression(new ClassExpression(ownerTypeName)); 1729 } 1730 else { 1731 loadThisOrOwner(); 1732 } 1733 1734 if (innerClass.getSuperClass().equals("groovy.lang.Closure")) { 1735 if (isStaticMethod()) { 1736 1740 visitClassExpression(new ClassExpression(ownerTypeName)); 1741 } 1742 else { 1743 loadThisOrOwner(); 1744 } 1745 } 1746 1747 1749 for (int i = 2; i < localVariableParams.length; i++) { 1751 Parameter param = localVariableParams[i]; 1752 String name = param.getName(); 1753 1754 if (variableStack.get(name) == null) { 1755 visitFieldExpression(new FieldExpression(classNode.getField(name))); 1756 } 1757 else { 1758 visitVariableExpression(new VariableExpression(name)); 1759 } 1760 } 1762 passingClosureParams = false; 1763 1764 cv.visitMethodInsn( 1767 INVOKESPECIAL, 1768 innerClassinternalName, 1769 "<init>", 1770 BytecodeHelper.getMethodDescriptor("void", localVariableParams)); 1771 } 1772 1773 1776 protected void loadThisOrOwner() { 1777 if (isInnerClass()) { 1778 visitFieldExpression(new FieldExpression(classNode.getField("owner"))); 1779 } 1780 else { 1781 cv.visitVarInsn(ALOAD, 0); 1782 } 1783 } 1784 1785 public void visitRegexExpression(RegexExpression expression) { 1786 expression.getRegex().visit(this); 1787 regexPattern.call(cv); 1788 } 1789 1790 1794 public void visitConstantExpression(ConstantExpression expression) { 1795 Object value = expression.getValue(); 1796 helper.loadConstant(value); 1797 } 1798 1799 public void visitNegationExpression(NegationExpression expression) { 1800 Expression subExpression = expression.getExpression(); 1801 subExpression.visit(this); 1802 negation.call(cv); 1803 } 1804 1805 public void visitCastExpression(CastExpression expression) { 1806 String type = expression.getType(); 1807 type = checkValidType(type, expression, "in cast"); 1808 1809 visitAndAutoboxBoolean(expression.getExpression()); 1810 1811 doConvertAndCast(type, expression.getExpression()); 1812 } 1813 1814 public void visitNotExpression(NotExpression expression) { 1815 Expression subExpression = expression.getExpression(); 1816 subExpression.visit(this); 1817 1818 if (isComparisonExpression(expression.getExpression())) { 1823 notBoolean.call(cv); 1824 } 1825 else { 1826 notObject.call(cv); 1827 } 1828 } 1829 1830 1834 public void visitBooleanExpression(BooleanExpression expression) { 1835 expression.getExpression().visit(this); 1836 1837 if (!isComparisonExpression(expression.getExpression())) { 1838 asBool.call(cv); } 1844 } 1845 1846 public void visitMethodCallExpression(MethodCallExpression call) { 1847 onLineNumber(call, "visitMethodCallExpression: \"" + call.getMethod() + "\":"); 1848 if (ENABLE_EARLY_BINDING) 1849 call.resolve(this); 1850 1851 this.leftHandExpression = false; 1852 1853 Expression arguments = call.getArguments(); 1854 1860 boolean superMethodCall = MethodCallExpression.isSuperMethodCall(call); 1861 String method = call.getMethod(); 1862 if (superMethodCall && method.equals("<init>")) { 1863 1864 cv.visitVarInsn(ALOAD, 0); 1865 if (isInClosureConstructor()) { cv.visitVarInsn(ALOAD, 2); 1867 cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "(Ljava/lang/Object;)V"); 1868 } 1869 else { 1870 cv.visitVarInsn(ALOAD, 1); 1871 cv.visitMethodInsn(INVOKESPECIAL, internalBaseClassName, "<init>", "(Ljava/lang/Object;)V"); 1872 } 1873 } 1874 else { 1875 if (isThisExpression(call.getObjectExpression()) && isFieldOrVariable(call.getMethod())) { 1877 1884 1885 visitVariableExpression(new VariableExpression(method)); 1887 arguments.visit(this); 1888 invokeClosureMethod.call(cv); 1889 } 1890 else { 1891 if (superMethodCall) { 1892 if (method.equals("super") || method.equals("<init>")) { 1893 ConstructorNode superConstructorNode = findSuperConstructor(call); 1894 1895 cv.visitVarInsn(ALOAD, 0); 1896 1897 loadArguments(superConstructorNode.getParameters(), arguments); 1898 1899 String descriptor = BytecodeHelper.getMethodDescriptor("void", superConstructorNode.getParameters()); 1900 cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(classNode.getSuperClass()), "<init>", descriptor); 1901 } 1902 else { 1903 MethodNode superMethodNode = findSuperMethod(call); 1904 1905 cv.visitVarInsn(ALOAD, 0); 1906 1907 loadArguments(superMethodNode.getParameters(), arguments); 1908 1909 String descriptor = BytecodeHelper.getMethodDescriptor(superMethodNode.getReturnType(), superMethodNode.getParameters()); 1910 cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(superMethodNode.getDeclaringClass().getName()), method, descriptor); 1911 } 1912 } 1913 else { 1914 if (ENABLE_EARLY_BINDING) { 1916 try { 1917 MetaMethod metamethod = call.getMetaMethod(); if (metamethod != null) { 1919 Class decClass = metamethod.getDeclaringClass(); 1920 String ownerClassName = null; 1921 if (decClass == null) { 1922 ownerClassName = BytecodeHelper.getClassInternalName(classNode.getName()); 1924 } 1925 else { 1926 ownerClassName = BytecodeHelper.getClassInternalName(decClass.getName()); 1927 } 1928 1929 String methodName = call.getMethod(); 1930 String descr = BytecodeHelper.getMethodDescriptor(metamethod); 1931 Class [] params = metamethod.getParameterTypes(); 1932 Label l2 = new Label(); 1934 1935 if (metamethod.isStatic()) { 1936 } else { 1937 boolean wasLeft = leftHandExpression; 1938 leftHandExpression = false; 1939 call.getObjectExpression().visit(this); 1940 1941 if (call.isSafe()) { 1942 helper.dup(); 1943 cv.visitJumpInsn(IFNULL, l2); 1944 } 1945 1946 cv.visitTypeInsn(CHECKCAST, ownerClassName); 1947 leftHandExpression = wasLeft; 1948 } 1949 if (arguments instanceof TupleExpression) { 1951 TupleExpression tupleExpression = (TupleExpression) arguments; 1952 List argexps = tupleExpression.getExpressions(); 1953 for (int i = 0; i < argexps.size(); i++) { 1954 Expression expression = (Expression) argexps.get(i); 1955 load(expression); 1956 1957 if (params[i].isPrimitive() ) { cast(params[i]); 1959 helper.quickUnboxIfNecessary(params[i]); 1960 } 1961 else if (params[i].isArray() && params[i].getComponentType().isPrimitive() ) { 1962 new ClassExpression(params[i].getComponentType()).visit(this); 1963 convertToPrimitiveArray.call(cv); 1964 cast(params[i]); 1965 } 1966 else { 1967 if (expression.getTypeClass() == GString.class && params[i] == String .class){ 1968 cast(GString.class); 1969 cv.visitMethodInsn( 1970 INVOKEVIRTUAL, 1971 "java/lang/Object", 1972 "toString", 1973 "()Ljava/lang/String;" 1974 ); 1975 } 1976 else { 1977 cast(params[i]); 1978 } 1979 } 1980 } 1981 if (metamethod.isStatic()) { 1982 cv.visitMethodInsn(INVOKESTATIC, ownerClassName, methodName, descr); 1983 } 1984 else if (decClass != null && decClass.isInterface()){ 1985 cv.visitMethodInsn(INVOKEINTERFACE, ownerClassName, methodName, descr); 1986 } 1987 else { 1988 cv.visitMethodInsn(INVOKEVIRTUAL, ownerClassName, methodName, descr); 1989 } 1990 call.setTypeClass(metamethod.getReturnType()); 1991 if (metamethod.getReturnType().isPrimitive() 1992 && metamethod.getReturnType() != void.class 1993 ) { 1995 helper.quickBoxIfNecessary(metamethod.getReturnType()); 1996 } 1997 if (call.isSafe()) { 1998 Label l3 = new Label(); 1999 cv.visitJumpInsn(GOTO, l3); 2000 cv.visitLabel(l2); 2001 cv.visitInsn(POP); 2002 cv.visitInsn(ACONST_NULL); 2003 cv.visitLabel(l3); 2004 } 2005 return; 2006 } else { 2007 throw new GroovyRuntimeException("arguments type not handled. fall through to late binding"); 2008 } 2009 } 2010 } catch (Exception e) { 2011 } 2016 } 2018 if (emptyArguments(arguments) && !call.isSafe()) { 2019 call.getObjectExpression().visit(this); 2020 cv.visitLdcInsn(method); 2021 invokeNoArgumentsMethod.call(cv); } 2023 else { 2024 if (argumentsUseStack(arguments)) { 2025 2026 arguments.visit(this); 2027 2028 Variable tv = visitASTOREInTemp(method + "_arg"); 2029 int paramIdx = tv.getIndex(); 2030 2031 call.getObjectExpression().visit(this); 2033 cv.visitLdcInsn(method); 2034 2035 cv.visitVarInsn(ALOAD, paramIdx); 2036 removeVar(tv); 2037 } 2038 else { 2039 call.getObjectExpression().visit(this); 2040 cv.visitLdcInsn(method); 2041 arguments.visit(this); 2042 } 2043 2044 if (call.isSafe()) { 2045 invokeMethodSafeMethod.call(cv); 2046 } 2047 else { 2048 invokeMethodMethod.call(cv); 2049 } 2050 } 2051 } 2052 } 2053 } 2054 } 2055 2056 2059 protected void loadArguments(Parameter[] parameters, Expression expression) { 2060 TupleExpression argListExp = (TupleExpression) expression; 2061 List arguments = argListExp.getExpressions(); 2062 for (int i = 0, size = arguments.size(); i < size; i++) { 2063 Expression argExp = argListExp.getExpression(i); 2064 Parameter param = parameters[i]; 2065 visitAndAutoboxBoolean(argExp); 2066 2067 String type = param.getType(); 2068 if (BytecodeHelper.isPrimitiveType(type)) { 2069 helper.unbox(type); 2070 } 2071 2072 String expType = getExpressionType(argExp); 2073 if (isValidTypeForCast(type) && (expType == null || !type.equals(expType))) { 2074 doConvertAndCast(type); 2075 } 2076 } 2078 } 2079 2080 2083 protected MethodNode findSuperMethod(MethodCallExpression call) { 2084 String methodName = call.getMethod(); 2085 TupleExpression argExpr = (TupleExpression) call.getArguments(); 2086 int argCount = argExpr.getExpressions().size(); 2087 ClassNode superClassNode = classNode.getSuperClassNode(); 2088 if (superClassNode != null) { 2089 List methods = superClassNode.getMethods(methodName); 2090 for (Iterator iter = methods.iterator(); iter.hasNext(); ) { 2091 MethodNode method = (MethodNode) iter.next(); 2092 if (method.getParameters().length == argCount) { 2093 return method; 2094 } 2095 } 2096 } 2097 throwException("No such method: " + methodName + " for class: " + classNode.getName()); 2098 return null; } 2100 2101 2104 protected ConstructorNode findSuperConstructor(MethodCallExpression call) { 2105 TupleExpression argExpr = (TupleExpression) call.getArguments(); 2106 int argCount = argExpr.getExpressions().size(); 2107 ClassNode superClassNode = classNode.getSuperClassNode(); 2108 if (superClassNode != null) { 2109 List constructors = superClassNode.getDeclaredConstructors(); 2110 for (Iterator iter = constructors.iterator(); iter.hasNext(); ) { 2111 ConstructorNode constructor = (ConstructorNode) iter.next(); 2112 if (constructor.getParameters().length == argCount) { 2113 return constructor; 2114 } 2115 } 2116 } 2117 throwException("No such constructor for class: " + classNode.getName()); 2118 return null; } 2120 2121 protected boolean emptyArguments(Expression arguments) { 2122 if (arguments instanceof TupleExpression) { 2123 TupleExpression tupleExpression = (TupleExpression) arguments; 2124 int size = tupleExpression.getExpressions().size(); 2125 return size == 0; 2126 } 2127 return false; 2128 } 2129 2130 public void visitStaticMethodCallExpression(StaticMethodCallExpression call) { 2131 this.leftHandExpression = false; 2132 2133 Expression arguments = call.getArguments(); 2134 if (emptyArguments(arguments)) { 2135 cv.visitLdcInsn(call.getType()); 2136 cv.visitLdcInsn(call.getMethod()); 2137 2138 invokeStaticNoArgumentsMethod.call(cv); 2139 } 2140 else { 2141 if (arguments instanceof TupleExpression) { 2142 TupleExpression tupleExpression = (TupleExpression) arguments; 2143 int size = tupleExpression.getExpressions().size(); 2144 if (size == 1) { 2145 arguments = (Expression) tupleExpression.getExpressions().get(0); 2146 } 2147 } 2148 2149 cv.visitLdcInsn(call.getOwnerType()); 2150 cv.visitLdcInsn(call.getMethod()); 2151 arguments.visit(this); 2152 2153 invokeStaticMethodMethod.call(cv); 2154 } 2155 } 2156 2157 public void visitConstructorCallExpression(ConstructorCallExpression call) { 2158 onLineNumber(call, "visitConstructorCallExpression: \"" + call.getTypeToSet() + "\":"); 2159 do { 2160 if (ENABLE_EARLY_BINDING) { 2161 call.resolve(this); 2162 if (call.isResolveFailed() || call.getTypeClass() == null) { 2163 break; 2164 } 2165 else { 2166 try { 2167 Constructor ctor = call.getConstructor(); if (ctor != null) { 2169 Class decClass = ctor.getDeclaringClass(); 2170 String ownerClassName = null; 2171 if (decClass == null) { 2172 ownerClassName = BytecodeHelper.getClassInternalName(classNode.getName()); 2174 } 2175 else { 2176 ownerClassName = BytecodeHelper.getClassInternalName(decClass.getName()); 2177 } 2178 2179 Class [] params = ctor.getParameterTypes(); 2180 StringBuffer argbuf = new StringBuffer ("("); 2181 for (int i = 0; i < params.length; i++) { 2182 Class arg = params[i]; 2183 String descr = BytecodeHelper.getTypeDescription(arg); 2184 argbuf.append(descr); 2185 } 2186 argbuf.append(")V"); 2187 cv.visitTypeInsn(NEW, ownerClassName); 2189 cv.visitInsn(DUP); 2190 2191 Expression arguments = call.getArguments(); 2193 if (arguments instanceof TupleExpression) { 2194 TupleExpression tupleExpression = (TupleExpression) arguments; 2195 List argexps = tupleExpression.getExpressions(); 2196 for (int i = 0; i < argexps.size(); i++) { 2197 Expression expression = (Expression) argexps.get(i); 2198 load(expression); 2199 if (params[i].isPrimitive() ) { cast(params[i]); 2201 helper.quickUnboxIfNecessary(params[i]); 2202 } 2203 else if (params[i].isArray() && params[i].getComponentType().isPrimitive() ) { 2204 new ClassExpression(params[i].getComponentType()).visit(this); 2205 convertToPrimitiveArray.call(cv); 2206 cast(params[i]); 2207 } 2208 else { 2209 if (expression.getTypeClass() == GString.class && params[i] == String .class){ 2211 cast(GString.class); 2212 cv.visitMethodInsn( 2213 INVOKEVIRTUAL, 2214 "java/lang/Object", 2215 "toString", 2216 "()Ljava/lang/String;" 2217 ); 2218 } 2219 else { 2220 cast(params[i]); 2221 } 2222 } 2223 } 2224 2225 cv.visitMethodInsn(INVOKESPECIAL, ownerClassName, "<init>", argbuf.toString()); 2226 return; 2227 } else { 2228 throw new GroovyRuntimeException("arguments type not handled. fall through to late binding"); 2229 } 2230 } 2231 } catch (Exception e) { 2232 break; } 2237 } 2238 } 2239 } while(false); 2240 2241 this.leftHandExpression = false; 2242 2243 Expression arguments = call.getArguments(); 2244 if (arguments instanceof TupleExpression) { 2245 TupleExpression tupleExpression = (TupleExpression) arguments; 2246 int size = tupleExpression.getExpressions().size(); 2247 if (size == 0) { 2248 arguments = null; 2249 } 2250 } 2254 2255 String type = checkValidType(call.getType(), call, "in constructor call"); 2257 2258 2260 visitClassExpression(new ClassExpression(type)); 2261 if (arguments !=null) { 2262 arguments.visit(this); 2263 invokeConstructorOfMethod.call(cv); } else { 2265 invokeNoArgumentsConstructorOf.call(cv); } 2267 2274 } 2275 2276 public void visitPropertyExpression(PropertyExpression expression) { 2277 2278 do { 2279 if (true && ENABLE_EARLY_BINDING) { 2280 expression.resolve(this); 2281 2282 if (!expression.isTypeResolved()) { 2283 break; 2284 } 2285 Expression ownerExp = expression.getObjectExpression(); 2286 String propName = expression.getProperty(); 2287 if (expression.getProperty().equals("class")) { 2288 break; } 2290 2291 2292 String ownerType = ownerExp.getType(); 2293 Class ownerClass = ownerExp.getTypeClass(); 2294 if (ownerType == null || ownerType.length() == 0) { 2295 break; 2296 } 2297 2298 Label l3 = new Label(); 2299 if (ownerClass != null && ownerClass.isArray() && propName.equals("length")) { 2301 load(ownerExp); 2302 if (expression.isSafe()) { 2303 helper.dup(); 2304 cv.visitJumpInsn(IFNULL, l3); 2305 } 2306 cast(ownerClass); 2307 cv.visitInsn(ARRAYLENGTH); 2308 helper.quickBoxIfNecessary(int.class); 2309 cv.visitLabel(l3); 2310 return; 2311 } 2312 2313 2314 String propertyType = expression.getType(); 2315 if (propertyType == null || propertyType.length() == 0) { 2316 break; 2317 } 2318 boolean isStatic = expression.isStatic(); 2319 if (!isThisExpression(ownerExp) && GroovyObject.class.isAssignableFrom(ownerExp.getTypeClass())) { 2320 if (!isStatic && ownerExp instanceof ClassExpression) { 2322 if (leftHandExpression) { 2323 cv.visitMethodInsn( 2324 INVOKEVIRTUAL, 2325 BytecodeHelper.getClassInternalName(ownerType), 2326 "setProperty", 2327 BytecodeHelper.getTypeDescription(propertyType)); 2328 } else { 2329 cv.visitMethodInsn( 2330 INVOKEVIRTUAL, 2331 BytecodeHelper.getClassInternalName(ownerType), 2332 "getProperty", 2333 BytecodeHelper.getTypeDescription(propertyType)); 2334 } 2335 return; 2336 } else { 2337 break; 2338 } 2339 } 2340 2358 else { Field fld = expression.getField(); 2361 Method setter = expression.getSetter(); 2362 Method getter = expression.getGetter(); 2363 2364 if (leftHandExpression) { 2366 if (fld == null && setter == null) { 2367 break; 2368 } 2369 } 2370 else { 2371 if (fld == null && getter == null) { 2372 break; 2373 } 2374 } 2375 2376 if (ownerClass == null && !isThisExpression(ownerExp)) { 2377 break; } 2379 2381 2382 if (expression.isStatic()) { 2383 if (leftHandExpression) { 2384 if (fld != null) { 2385 helper.quickUnboxIfNecessary(expression.getTypeClass()); 2386 cv.visitFieldInsn( 2387 PUTSTATIC, 2388 BytecodeHelper.getClassInternalName(ownerType), 2389 expression.getProperty(), 2390 BytecodeHelper.getTypeDescription(propertyType) 2391 ); 2392 } 2393 else if (setter != null) { 2394 helper.quickUnboxIfNecessary(setter.getParameterTypes()[0]); 2395 cast(setter.getParameterTypes()[0]); 2396 helper.invoke(setter); 2397 } 2398 else { 2399 throwException("no method or field is found for a resolved property access"); 2400 } 2401 } 2402 else { if (fld != null){ 2404 cv.visitFieldInsn( 2405 GETSTATIC, 2406 BytecodeHelper.getClassInternalName(ownerType), 2407 propName, 2408 BytecodeHelper.getTypeDescription(propertyType) 2409 ); 2410 helper.quickBoxIfNecessary(expression.getTypeClass()); 2411 } 2412 else if (getter != null) { 2413 helper.invoke(getter); 2414 helper.quickBoxIfNecessary(expression.getTypeClass()); 2415 } 2416 else { 2417 throwException("no method or field is found for a resolved property access"); 2418 } 2419 } 2420 } else { if (leftHandExpression) { helper.quickUnboxIfNecessary(expression.getTypeClass()); 2424 load(ownerExp); 2425 if (expression.isSafe()) { 2426 helper.dup(); 2427 cv.visitJumpInsn(IFNULL, l3); 2428 } 2429 2430 if (ownerClass != null) 2431 cast(ownerClass); 2432 Class cls = expression.getTypeClass(); 2433 if (cls == double.class || cls == long.class) { 2434 cv.visitInsn(DUP_X2); 2435 cv.visitInsn(POP); 2436 } else { 2437 cv.visitInsn(SWAP); 2438 } 2439 2440 if (fld != null) { 2441 cv.visitFieldInsn( 2442 PUTFIELD, 2443 BytecodeHelper.getClassInternalName(ownerType), 2444 propName, 2445 BytecodeHelper.getTypeDescription(propertyType) 2446 ); 2447 } 2448 else if (setter != null) { 2449 Method m = setter; 2450 Class [] paramTypes = m.getParameterTypes(); 2451 if (paramTypes.length != 1) { 2452 throw new RuntimeException ("setter should take a single parameter"); 2453 } 2454 Class paramType = paramTypes[0]; 2455 cast(paramType); 2456 helper.invoke(setter); 2457 } 2458 else { 2459 throwException("no method or field is found for a resolved property access"); 2460 } 2461 } 2462 else { load(ownerExp); 2464 if (expression.isSafe()) { 2465 helper.dup(); 2466 cv.visitJumpInsn(IFNULL, l3); 2467 } 2468 if (ownerClass != null) 2469 cast(ownerClass); 2470 if (fld != null) { 2471 cv.visitFieldInsn( 2472 GETFIELD, 2473 BytecodeHelper.getClassInternalName(ownerType), 2474 propName, 2475 BytecodeHelper.getTypeDescription(propertyType) 2476 ); 2477 helper.quickBoxIfNecessary(expression.getTypeClass()); 2478 } 2479 else if (getter != null) { 2480 helper.invoke(getter); 2481 helper.quickBoxIfNecessary(expression.getTypeClass()); 2482 } 2483 else { 2484 throwException("no method or field is found for a resolved property access"); 2485 } 2486 } 2487 } 2488 cv.visitLabel(l3); 2489 return; 2490 } 2491 } 2492 } while (false); 2493 2494 String className = null; 2496 Expression objectExpression = expression.getObjectExpression(); 2497 if (!isThisExpression(objectExpression)) { 2498 className = checkForQualifiedClass(expression); 2499 if (className != null) { 2500 visitClassExpression(new ClassExpression(className)); 2501 return; 2502 } 2503 } 2504 if (expression.getProperty().equals("class")) { 2505 if ((objectExpression instanceof ClassExpression)) { 2506 visitClassExpression((ClassExpression) objectExpression); 2507 return; 2508 } 2509 else if (objectExpression instanceof VariableExpression) { 2510 VariableExpression varExp = (VariableExpression) objectExpression; 2511 className = varExp.getVariable(); 2512 try { 2513 className = resolveClassName(className); 2514 visitClassExpression(new ClassExpression(className)); 2515 return; 2516 } 2517 catch (Exception e) { 2518 } 2520 } 2521 } 2522 2523 if (isThisExpression(objectExpression)) { 2524 String name = expression.getProperty(); 2526 FieldNode field = classNode.getField(name); 2527 if (field != null) { 2528 visitFieldExpression(new FieldExpression(field)); 2529 return; 2530 } 2531 } 2532 2533 boolean left = leftHandExpression; 2534 leftHandExpression = false; 2537 2538 objectExpression.visit(this); 2539 2540 cv.visitLdcInsn(expression.getProperty()); 2541 2542 if (isGroovyObject(objectExpression) && ! expression.isSafe()) { 2543 if (left) { 2544 setGroovyObjectPropertyMethod.call(cv); 2545 } 2546 else { 2547 getGroovyObjectPropertyMethod.call(cv); 2548 } 2549 } 2550 else { 2551 if (expression.isSafe()) { 2552 if (left) { 2553 setPropertySafeMethod2.call(cv); 2554 } 2555 else { 2556 getPropertySafeMethod.call(cv); 2557 } 2558 } 2559 else { 2560 if (left) { 2561 setPropertyMethod2.call(cv); 2562 } 2563 else { 2564 getPropertyMethod.call(cv); 2565 } 2566 } 2567 } 2568 } 2569 2570 protected boolean isGroovyObject(Expression objectExpression) { 2571 return isThisExpression(objectExpression); 2572 } 2573 2574 2578 protected String checkForQualifiedClass(PropertyExpression expression) { 2579 String text = expression.getText(); 2580 if (text != null && text.endsWith(".class")) { 2581 text = text.substring(0, text.length() - 6); 2582 } 2583 try { 2584 return resolveClassName(text); 2585 } 2586 catch (Exception e) { 2587 return null; 2588 } 2589 } 2590 2591 public void visitFieldExpression(FieldExpression expression) { 2592 FieldNode field = expression.getField(); 2593 2594 2595 if (field.isStatic()) { 2596 if (leftHandExpression) { 2597 storeStaticField(expression); 2598 } 2599 else { 2600 loadStaticField(expression); 2601 } 2602 } else { 2603 if (leftHandExpression) { 2604 storeThisInstanceField(expression); 2605 } 2606 else { 2607 loadInstanceField(expression); 2608 } 2609 } 2610 } 2611 2612 2616 public void loadStaticField(FieldExpression fldExp) { 2617 FieldNode field = fldExp.getField(); 2618 boolean holder = field.isHolder() && !isInClosureConstructor(); 2619 String type = field.getType(); 2620 2621 String ownerName = (field.getOwner().equals(classNode.getName())) 2622 ? internalClassName 2623 : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner())); 2624 if (holder) { 2625 cv.visitFieldInsn(GETSTATIC, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type)); 2626 cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;"); 2627 } 2628 else { 2629 cv.visitFieldInsn(GETSTATIC, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type)); 2630 if (BytecodeHelper.isPrimitiveType(type)) { 2631 helper.box(type); 2632 } else { 2633 } 2634 } 2635 } 2636 2637 2641 public void loadInstanceField(FieldExpression fldExp) { 2642 FieldNode field = fldExp.getField(); 2643 boolean holder = field.isHolder() && !isInClosureConstructor(); 2644 String type = field.getType(); 2645 String ownerName = (field.getOwner().equals(classNode.getName())) 2646 ? internalClassName 2647 : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner())); 2648 2649 cv.visitVarInsn(ALOAD, 0); 2650 cv.visitFieldInsn(GETFIELD, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type)); 2651 2652 if (holder) { 2653 cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;"); 2654 } else { 2655 if (BytecodeHelper.isPrimitiveType(type)) { 2656 helper.box(type); 2657 } else { 2658 } 2659 } 2660 } 2661 2662 public void storeThisInstanceField(FieldExpression expression) { 2663 FieldNode field = expression.getField(); 2664 2665 boolean holder = field.isHolder() && !isInClosureConstructor(); 2666 String type = field.getType(); 2667 2668 String ownerName = (field.getOwner().equals(classNode.getName())) ? 2669 internalClassName : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner())); 2670 if (holder) { 2671 Variable tv = visitASTOREInTemp(field.getName()); 2672 int tempIndex = tv.getIndex(); 2673 cv.visitVarInsn(ALOAD, 0); 2674 cv.visitFieldInsn(GETFIELD, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type)); 2675 cv.visitVarInsn(ALOAD, tempIndex); 2676 cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V"); 2677 removeVar(tv); 2678 } 2679 else { 2680 if (isInClosureConstructor()) { 2681 helper.doCast(type); 2682 } 2683 else { 2684 if (ENABLE_EARLY_BINDING) { 2685 helper.doCast(type); 2686 } 2687 else { 2688 doConvertAndCast(type); 2690 } 2691 } 2692 Variable tmpVar = defineVariable(createVariableName(field.getName()), field.getType(), false); 2694 helper.store(tmpVar, MARK_START); 2697 helper.loadThis(); helper.load(tmpVar); 2699 helper.putField(field, ownerName); 2700 removeVar(tmpVar); 2703 } 2704 } 2705 2706 2707 public void storeStaticField(FieldExpression expression) { 2708 FieldNode field = expression.getField(); 2709 2710 boolean holder = field.isHolder() && !isInClosureConstructor(); 2711 2712 String type = field.getType(); 2713 2714 String ownerName = (field.getOwner().equals(classNode.getName())) 2715 ? internalClassName 2716 : org.objectweb.asm.Type.getInternalName(loadClass(field.getOwner())); 2717 if (holder) { 2718 Variable tv = visitASTOREInTemp(field.getName()); 2719 int tempIndex = tv.getIndex(); 2720 cv.visitFieldInsn(GETSTATIC, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type)); 2721 cv.visitVarInsn(ALOAD, tempIndex); 2722 cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V"); 2723 removeVar(tv); 2724 } 2725 else { 2726 if (isInClosureConstructor()) { 2727 helper.doCast(type); 2728 } 2729 else { 2730 if (ENABLE_EARLY_BINDING) { 2731 helper.doCast(type); 2732 } 2733 else { 2734 helper.doCast(type); 2738 } 2739 } 2740 cv.visitFieldInsn(PUTSTATIC, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type)); 2741 } 2742 } 2743 2744 protected void visitOuterFieldExpression(FieldExpression expression, ClassNode outerClassNode, int steps, boolean first ) { 2745 FieldNode field = expression.getField(); 2746 boolean isStatic = field.isStatic(); 2747 2748 Variable fieldTemp = defineVariable(createVariableName(field.getName()), "java.lang.Object", false); 2749 int valueIdx = fieldTemp.getIndex(); 2750 2751 if (leftHandExpression && first) { 2752 cv.visitVarInsn(ASTORE, valueIdx); 2753 visitVariableStartLabel(fieldTemp); 2754 } 2755 2756 if (steps > 1 || !isStatic) { 2757 cv.visitVarInsn(ALOAD, 0); 2758 cv.visitFieldInsn( 2759 GETFIELD, 2760 internalClassName, 2761 "owner", 2762 BytecodeHelper.getTypeDescription(outerClassNode.getName())); 2763 } 2764 2765 if( steps == 1 ) { 2766 int opcode = (leftHandExpression) ? ((isStatic) ? PUTSTATIC : PUTFIELD) : ((isStatic) ? GETSTATIC : GETFIELD); 2767 String ownerName = BytecodeHelper.getClassInternalName(outerClassNode.getName()); 2768 2769 if (leftHandExpression) { 2770 cv.visitVarInsn(ALOAD, valueIdx); 2771 boolean holder = field.isHolder() && !isInClosureConstructor(); 2772 if ( !holder) { 2773 doConvertAndCast(field.getType()); 2774 } 2775 } 2776 cv.visitFieldInsn(opcode, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(field.getType())); 2777 if (!leftHandExpression) { 2778 if (BytecodeHelper.isPrimitiveType(field.getType())) { 2779 helper.box(field.getType()); 2780 } 2781 } 2782 } 2783 2784 else { 2785 visitOuterFieldExpression( expression, outerClassNode.getOuterClass(), steps - 1, false ); 2786 } 2787 } 2788 2789 2790 2791 2794 2795 public void visitVariableExpression(VariableExpression expression) { 2796 2797 String variableName = expression.getVariable(); 2798 2799 2802 2805 if (isStaticMethod() && variableName.equals("this")) { 2806 visitClassExpression(new ClassExpression(classNode.getName())); 2807 return; } 2809 2810 2813 if (variableName.equals("super")) { 2814 visitClassExpression(new ClassExpression(classNode.getSuperClass())); 2815 return; } 2817 2818 2819 2822 2835 2836 2839 2840 2848 boolean handled = false; 2849 Variable variable = (Variable)variableStack.get( variableName ); 2850 2851 if( variable != null ) { 2852 2853 if( variable.isProperty() ) { 2854 processPropertyVariable(variable ); 2855 } 2856 else { 2857 if (ENABLE_EARLY_BINDING && expression.isTypeResolved() && leftHandExpression) { 2858 String typeName = expression.getType(); 2860 Type varOldType = variable.getType(); 2861 if (varOldType.isDynamic()) { 2862 variable.setType(new Type(typeName, true)); 2863 } 2864 else if (!varOldType.getName().equals(typeName)){ 2865 new GroovyRuntimeException("VariableExpression data type conflicts with the existing variable. " 2866 + "[" + expression.getLineNumber() + ":" + expression.getColumnNumber() + "]"); 2867 } 2868 } 2869 processStackVariable(variable ); 2870 } 2871 2872 handled = true; 2873 } else { 2874 2877 int steps = 0; 2878 ClassNode currentClassNode = classNode; 2879 FieldNode field = null; 2880 2881 do { 2882 if( (field = currentClassNode.getField(variableName)) != null ) { 2883 if (methodNode == null || !methodNode.isStatic() || field.isStatic() ) 2884 break; } 2886 steps++; 2887 2888 } while( (currentClassNode = currentClassNode.getOuterClass()) != null ); 2889 2890 if( field != null ) { 2891 processFieldAccess( variableName, field, steps ); 2892 handled = true; 2893 } 2894 } 2895 2896 if (!handled && !variableName.equals("this")) { 2899 String className = resolveClassName(variableName); 2900 if (className != null) { 2901 if (leftHandExpression) { 2902 throwException("Cannot use a class expression on the left hand side of an assignment"); 2903 } 2904 visitClassExpression(new ClassExpression(className)); 2905 return; } 2907 } 2908 2909 2916 if( !handled ) { 2917 String variableType = expression.getType(); 2918 variable = defineVariable( variableName, variableType ); 2919 2920 if (leftHandExpression && expression.isDynamic()) { 2921 variable.setDynamic(true); } 2923 else { 2924 variable.setDynamic(false); 2925 } 2926 2927 if( isInScriptBody() || !leftHandExpression ) { variable.setProperty( true ); 2929 processPropertyVariable(variable ); 2930 } 2931 else { 2932 processStackVariable(variable ); 2933 } 2934 } 2935 } 2936 2937 2938 protected void processStackVariable(Variable variable ) { 2939 boolean holder = variable.isHolder() && !passingClosureParams; 2940 2941 if( leftHandExpression ) { 2942 helper.storeVar(variable, holder); 2943 } 2944 else { 2945 helper.loadVar(variable, holder); 2946 } 2947 if (ASM_DEBUG) { 2948 helper.mark("var: " + variable.getName()); 2949 } 2950 } 2951 2952 private void visitVariableStartLabel(Variable variable) { 2953 if (CREATE_DEBUG_INFO) { 2954 Label l = variable.getStartLabel(); 2955 if (l != null) { 2956 cv.visitLabel(l); 2957 } else { 2958 System.out.println("start label == null! what to do about this?"); 2959 } 2960 } 2961 } 2962 2963 protected void processPropertyVariable(Variable variable ) { 2964 String name = variable.getName(); 2965 if (variable.isHolder() && passingClosureParams && isInScriptBody() ) { 2966 cv.visitTypeInsn(NEW, "org/codehaus/groovy/runtime/ScriptReference"); 2968 cv.visitInsn(DUP); 2969 2970 loadThisOrOwner(); 2971 cv.visitLdcInsn(name); 2972 2973 cv.visitMethodInsn( 2974 INVOKESPECIAL, 2975 "org/codehaus/groovy/runtime/ScriptReference", 2976 "<init>", 2977 "(Lgroovy/lang/Script;Ljava/lang/String;)V"); 2978 } 2979 else { 2980 visitPropertyExpression(new PropertyExpression(VariableExpression.THIS_EXPRESSION, name)); 2981 } 2982 } 2983 2984 2985 protected void processFieldAccess( String name, FieldNode field, int steps ) { 2986 FieldExpression expression = new FieldExpression(field); 2987 2988 if( steps == 0 ) { 2989 visitFieldExpression( expression ); 2990 } 2991 else { 2992 visitOuterFieldExpression( expression, classNode.getOuterClass(), steps, true ); 2993 } 2994 } 2995 2996 2997 2998 3002 protected boolean isInScriptBody() { 3003 if (classNode.isScriptBody()) { 3004 return true; 3005 } 3006 else { 3007 return classNode.isScript() && methodNode != null && methodNode.getName().equals("run"); 3008 } 3009 } 3010 3011 3015 protected boolean isPopRequired(Expression expression) { 3016 if (expression instanceof MethodCallExpression) { 3017 if (expression.getType() != null && expression.getType().equals("void")) { return false; 3019 } else { 3020 return !MethodCallExpression.isSuperMethodCall((MethodCallExpression) expression); 3021 } 3022 } 3023 if (expression instanceof BinaryExpression) { 3024 BinaryExpression binExp = (BinaryExpression) expression; 3025 switch (binExp.getOperation().getType()) { } 3035 } 3036 return true; 3037 } 3038 3039 protected boolean firstStatementIsSuperInit(Statement code) { 3040 ExpressionStatement expStmt = null; 3041 if (code instanceof ExpressionStatement) { 3042 expStmt = (ExpressionStatement) code; 3043 } 3044 else if (code instanceof BlockStatement) { 3045 BlockStatement block = (BlockStatement) code; 3046 if (!block.getStatements().isEmpty()) { 3047 Object expr = block.getStatements().get(0); 3048 if (expr instanceof ExpressionStatement) { 3049 expStmt = (ExpressionStatement) expr; 3050 } 3051 } 3052 } 3053 if (expStmt != null) { 3054 Expression expr = expStmt.getExpression(); 3055 if (expr instanceof MethodCallExpression) { 3056 MethodCallExpression call = (MethodCallExpression) expr; 3057 if (MethodCallExpression.isSuperMethodCall(call)) { 3058 return call.getMethod().equals("<init>") || call.getMethod().equals("super"); 3060 } 3061 } 3062 } 3063 return false; 3064 } 3065 3066 protected void createSyntheticStaticFields() { 3067 for (Iterator iter = syntheticStaticFields.iterator(); iter.hasNext();) { 3068 String staticFieldName = (String ) iter.next(); 3069 cw.visitField(ACC_STATIC + ACC_SYNTHETIC, staticFieldName, "Ljava/lang/Class;", null, null); 3071 } 3072 3073 if (!syntheticStaticFields.isEmpty()) { 3074 cv = 3075 cw.visitMethod( 3076 ACC_STATIC + ACC_SYNTHETIC, 3077 "class$", 3078 "(Ljava/lang/String;)Ljava/lang/Class;", 3079 null, 3080 null); 3081 helper = new BytecodeHelper(cv); 3082 3083 Label l0 = new Label(); 3084 cv.visitLabel(l0); 3085 cv.visitVarInsn(ALOAD, 0); 3086 cv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;"); 3087 Label l1 = new Label(); 3088 cv.visitLabel(l1); 3089 cv.visitInsn(ARETURN); 3090 Label l2 = new Label(); 3091 cv.visitLabel(l2); 3092 cv.visitVarInsn(ASTORE, 1); 3093 cv.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError"); 3094 cv.visitInsn(DUP); 3095 cv.visitVarInsn(ALOAD, 1); 3096 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassNotFoundException", "getMessage", "()Ljava/lang/String;"); 3097 cv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoClassDefFoundError", "<init>", "(Ljava/lang/String;)V"); 3098 cv.visitInsn(ATHROW); 3099 cv.visitTryCatchBlock(l0, l2, l2, "java/lang/ClassNotFoundException"); cv.visitMaxs(3, 2); 3101 3102 cw.visitEnd(); 3103 } 3104 } 3105 3106 public void visitClassExpression(ClassExpression expression) { 3107 String type = expression.getText(); 3108 3110 3111 if (BytecodeHelper.isPrimitiveType(type)) { 3112 String objectType = BytecodeHelper.getObjectTypeForPrimitive(type); 3113 cv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(objectType), "TYPE", "Ljava/lang/Class;"); 3114 } 3115 else { 3116 final String staticFieldName = 3117 (type.equals(classNode.getName())) ? "class$0" : "class$" + type.replace('.', '$').replace('[', '_').replace(';', '_'); 3118 3119 syntheticStaticFields.add(staticFieldName); 3120 3121 cv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;"); 3122 Label l0 = new Label(); 3123 cv.visitJumpInsn(IFNONNULL, l0); 3124 cv.visitLdcInsn(type); 3125 cv.visitMethodInsn(INVOKESTATIC, internalClassName, "class$", "(Ljava/lang/String;)Ljava/lang/Class;"); 3126 cv.visitInsn(DUP); 3127 cv.visitFieldInsn(PUTSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;"); 3128 Label l1 = new Label(); 3129 cv.visitJumpInsn(GOTO, l1); 3130 cv.visitLabel(l0); 3131 cv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;"); 3132 cv.visitLabel(l1); 3133 } 3134 } 3135 3136 public void visitRangeExpression(RangeExpression expression) { 3137 leftHandExpression = false; 3138 expression.getFrom().visit(this); 3139 3140 leftHandExpression = false; 3141 expression.getTo().visit(this); 3142 3143 helper.pushConstant(expression.isInclusive()); 3144 3145 createRangeMethod.call(cv); 3146 } 3147 3148 public void visitMapEntryExpression(MapEntryExpression expression) { 3149 } 3150 3151 public void visitMapExpression(MapExpression expression) { 3152 List entries = expression.getMapEntryExpressions(); 3153 int size = entries.size(); 3154 helper.pushConstant(size * 2); 3155 3156 cv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); 3157 3158 int i = 0; 3159 for (Iterator iter = entries.iterator(); iter.hasNext();) { 3160 MapEntryExpression entry = (MapEntryExpression) iter.next(); 3161 3162 cv.visitInsn(DUP); 3163 helper.pushConstant(i++); 3164 visitAndAutoboxBoolean(entry.getKeyExpression()); 3165 cv.visitInsn(AASTORE); 3166 3167 cv.visitInsn(DUP); 3168 helper.pushConstant(i++); 3169 visitAndAutoboxBoolean(entry.getValueExpression()); 3170 cv.visitInsn(AASTORE); 3171 } 3172 createMapMethod.call(cv); 3173 } 3174 3175 public void visitTupleExpression(TupleExpression expression) { 3176 int size = expression.getExpressions().size(); 3177 3178 helper.pushConstant(size); 3179 3180 cv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); 3181 3182 for (int i = 0; i < size; i++) { 3183 cv.visitInsn(DUP); 3184 helper.pushConstant(i); 3185 visitAndAutoboxBoolean(expression.getExpression(i)); 3186 cv.visitInsn(AASTORE); 3187 } 3188 } 3190 3191 public void visitArrayExpression(ArrayExpression expression) { 3192 String type = expression.getElementType(); 3193 String typeName = BytecodeHelper.getClassInternalName(type); 3194 Expression sizeExpression = expression.getSizeExpression(); 3195 if (sizeExpression != null) { 3196 visitAndAutoboxBoolean(sizeExpression); 3198 asIntMethod.call(cv); 3199 3200 cv.visitTypeInsn(ANEWARRAY, typeName); 3201 } 3202 else { 3203 int size = expression.getExpressions().size(); 3204 helper.pushConstant(size); 3205 3206 cv.visitTypeInsn(ANEWARRAY, typeName); 3207 3208 for (int i = 0; i < size; i++) { 3209 cv.visitInsn(DUP); 3210 helper.pushConstant(i); 3211 Expression elementExpression = expression.getExpression(i); 3212 if (elementExpression == null) { 3213 ConstantExpression.NULL.visit(this); 3214 } 3215 else { 3216 3217 if(!type.equals(elementExpression.getClass().getName())) { 3218 visitCastExpression(new CastExpression(type, elementExpression)); 3219 } 3220 else { 3221 visitAndAutoboxBoolean(elementExpression); 3222 } 3223 } 3224 cv.visitInsn(AASTORE); 3225 } 3226 } 3227 } 3228 3229 public void visitListExpression(ListExpression expression) { 3230 int size = expression.getExpressions().size(); 3231 helper.pushConstant(size); 3232 3233 cv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); 3234 3235 for (int i = 0; i < size; i++) { 3236 cv.visitInsn(DUP); 3237 helper.pushConstant(i); 3238 visitAndAutoboxBoolean(expression.getExpression(i)); 3239 cv.visitInsn(AASTORE); 3240 } 3241 createListMethod.call(cv); 3242 } 3243 3244 public void visitGStringExpression(GStringExpression expression) { 3245 int size = expression.getValues().size(); 3246 helper.pushConstant(size); 3247 3248 cv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); 3249 3250 for (int i = 0; i < size; i++) { 3251 cv.visitInsn(DUP); 3252 helper.pushConstant(i); 3253 visitAndAutoboxBoolean(expression.getValue(i)); 3254 cv.visitInsn(AASTORE); 3255 } 3256 3257 Variable tv = visitASTOREInTemp("iterator"); 3258 int paramIdx = tv.getIndex(); 3259 3260 ClassNode innerClass = createGStringClass(expression); 3261 addInnerClass(innerClass); 3262 String innerClassinternalName = BytecodeHelper.getClassInternalName(innerClass.getName()); 3263 3264 cv.visitTypeInsn(NEW, innerClassinternalName); 3265 cv.visitInsn(DUP); 3266 cv.visitVarInsn(ALOAD, paramIdx); 3267 3268 cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName, "<init>", "([Ljava/lang/Object;)V"); 3269 removeVar(tv); 3270 } 3271 3272 private Variable visitASTOREInTemp(String s) { 3273 return storeInTemp(s, "java.lang.Object"); 3274 } 3275 3276 protected boolean addInnerClass(ClassNode innerClass) { 3279 innerClass.setModule(classNode.getModule()); 3280 return innerClasses.add(innerClass); 3281 } 3282 3283 protected ClassNode createClosureClass(ClosureExpression expression) { 3284 ClassNode owner = getOutermostClass(); 3285 boolean parentIsInnerClass = owner instanceof InnerClassNode; 3286 String outerClassName = owner.getName(); 3287 String name = outerClassName + "$" 3288 + context.getNextClosureInnerName(owner, classNode, methodNode); boolean staticMethodOrInStaticClass = isStaticMethod() || classNode.isStaticClass(); 3290 if (staticMethodOrInStaticClass) { 3291 outerClassName = "java.lang.Class"; 3292 } 3293 Parameter[] parameters = expression.getParameters(); 3294 if (parameters == null || parameters.length == 0) { 3295 parameters = new Parameter[] { new Parameter("it")}; 3297 } 3298 3299 Parameter[] localVariableParams = getClosureSharedVariables(expression); 3300 3301 InnerClassNode answer = new InnerClassNode(owner, name, ACC_SUPER, "groovy.lang.Closure"); answer.setEnclosingMethod(this.methodNode); 3303 if (staticMethodOrInStaticClass) { 3304 answer.setStaticClass(true); 3305 } 3306 if (isInScriptBody()) { 3307 answer.setScriptBody(true); 3308 } 3309 MethodNode method = 3310 answer.addMethod("doCall", ACC_PUBLIC, "java.lang.Object", parameters, expression.getCode()); 3311 3312 method.setLineNumber(expression.getLineNumber()); 3313 method.setColumnNumber(expression.getColumnNumber()); 3314 3315 VariableScope varScope = expression.getVariableScope(); 3316 if (varScope == null) { 3317 throw new RuntimeException ( 3318 "Must have a VariableScope by now! for expression: " + expression + " class: " + name); 3319 } 3320 else { 3321 method.setVariableScope(varScope); 3322 } 3323 if (parameters.length > 1 3324 || (parameters.length == 1 3325 && parameters[0].getType() != null 3326 && !parameters[0].getType().equals("java.lang.Object"))) { 3327 3328 answer.addMethod( 3330 "call", 3331 ACC_PUBLIC, 3332 "java.lang.Object", 3333 parameters, 3334 new ReturnStatement( 3335 new MethodCallExpression( 3336 VariableExpression.THIS_EXPRESSION, 3337 "doCall", 3338 new ArgumentListExpression(parameters)))); 3339 } 3340 3341 FieldNode ownerField = answer.addField("owner", ACC_PRIVATE, outerClassName, null); 3342 3343 BlockStatement block = new BlockStatement(); 3345 block.addStatement( 3346 new ExpressionStatement( 3347 new MethodCallExpression( 3348 new VariableExpression("super"), 3349 "<init>", 3350 new VariableExpression("_outerInstance")))); 3351 block.addStatement( 3352 new ExpressionStatement( 3353 new BinaryExpression( 3354 new FieldExpression(ownerField), 3355 Token.newSymbol(Types.EQUAL, -1, -1), 3356 new VariableExpression("_outerInstance")))); 3357 3358 for (int i = 0; i < localVariableParams.length; i++) { 3360 Parameter param = localVariableParams[i]; 3361 String paramName = param.getName(); 3362 boolean holder = mutableVars.contains(paramName); 3363 Expression initialValue = null; 3364 String type = param.getType(); 3365 FieldNode paramField = null; 3366 if (holder) { 3367 initialValue = new VariableExpression(paramName); 3368 type = Reference.class.getName(); 3369 param.makeReference(); 3370 paramField = answer.addField(paramName, ACC_PRIVATE, type, initialValue); 3371 paramField.setHolder(true); 3372 String realType = param.getRealType(); 3373 String methodName = Verifier.capitalize(paramName); 3374 3375 Expression fieldExp = new FieldExpression(paramField); 3377 answer.addMethod( 3378 "get" + methodName, 3379 ACC_PUBLIC, 3380 realType, 3381 Parameter.EMPTY_ARRAY, 3382 new ReturnStatement(fieldExp)); 3383 3384 3393 } 3394 else { 3395 PropertyNode propertyNode = answer.addProperty(paramName, ACC_PUBLIC, type, initialValue, null, null); 3396 paramField = propertyNode.getField(); 3397 block.addStatement( 3398 new ExpressionStatement( 3399 new BinaryExpression( 3400 new FieldExpression(paramField), 3401 Token.newSymbol(Types.EQUAL, -1, -1), 3402 new VariableExpression(paramName)))); 3403 } 3404 } 3405 3406 Parameter[] params = new Parameter[2 + localVariableParams.length]; 3407 params[0] = new Parameter(outerClassName, "_outerInstance"); 3408 params[1] = new Parameter("java.lang.Object", "_delegate"); 3409 System.arraycopy(localVariableParams, 0, params, 2, localVariableParams.length); 3410 3411 answer.addConstructor(ACC_PUBLIC, params, block); 3412 return answer; 3413 } 3414 3415 protected ClassNode getOutermostClass() { 3416 if (outermostClass == null) { 3417 outermostClass = classNode; 3418 while (outermostClass instanceof InnerClassNode) { 3419 outermostClass = outermostClass.getOuterClass(); 3420 } 3421 } 3422 return outermostClass; 3423 } 3424 3425 protected ClassNode createGStringClass(GStringExpression expression) { 3426 ClassNode owner = classNode; 3427 if (owner instanceof InnerClassNode) { 3428 owner = owner.getOuterClass(); 3429 } 3430 String outerClassName = owner.getName(); 3431 String name = outerClassName + "$" + context.getNextInnerClassIdx(); 3432 InnerClassNode answer = new InnerClassNode(owner, name, ACC_SUPER, GString.class.getName()); 3433 answer.setEnclosingMethod(this.methodNode); 3434 FieldNode stringsField = 3435 answer.addField( 3436 "strings", 3437 ACC_PRIVATE , 3438 "java.lang.String[]", 3439 new ArrayExpression("java.lang.String", expression.getStrings())); 3440 answer.addMethod( 3441 "getStrings", 3442 ACC_PUBLIC, 3443 "java.lang.String[]", 3444 Parameter.EMPTY_ARRAY, 3445 new ReturnStatement(new FieldExpression(stringsField))); 3446 BlockStatement block = new BlockStatement(); 3448 block.addStatement( 3449 new ExpressionStatement( 3450 new MethodCallExpression(new VariableExpression("super"), "<init>", new VariableExpression("values")))); 3451 Parameter[] contructorParams = new Parameter[] { new Parameter("java.lang.Object[]", "values")}; 3452 answer.addConstructor(ACC_PUBLIC, contructorParams, block); 3453 return answer; 3454 } 3455 3456 protected void doConvertAndCast(String type) { 3457 if (!type.equals("java.lang.Object")) { 3458 3459 if (!type.endsWith("[]") && isValidTypeForCast(type)) { 3460 visitClassExpression(new ClassExpression(type)); 3461 asTypeMethod.call(cv); 3462 } 3463 3464 helper.doCast(type); 3465 } 3466 } 3467 3468 protected void evaluateLogicalOrExpression(BinaryExpression expression) { 3469 visitBooleanExpression(new BooleanExpression(expression.getLeftExpression())); 3470 Label l0 = new Label(); 3471 Label l2 = new Label(); 3472 cv.visitJumpInsn(IFEQ, l0); 3473 3474 cv.visitLabel(l2); 3475 3476 visitConstantExpression(ConstantExpression.TRUE); 3477 3478 Label l1 = new Label(); 3479 cv.visitJumpInsn(GOTO, l1); 3480 cv.visitLabel(l0); 3481 3482 visitBooleanExpression(new BooleanExpression(expression.getRightExpression())); 3483 3484 cv.visitJumpInsn(IFNE, l2); 3485 3486 visitConstantExpression(ConstantExpression.FALSE); 3487 cv.visitLabel(l1); 3488 } 3489 3490 protected void evaluateLogicalAndExpression(BinaryExpression expression) { 3493 visitBooleanExpression(new BooleanExpression(expression.getLeftExpression())); 3494 Label l0 = new Label(); 3495 cv.visitJumpInsn(IFEQ, l0); 3496 3497 visitBooleanExpression(new BooleanExpression(expression.getRightExpression())); 3498 3499 cv.visitJumpInsn(IFEQ, l0); 3500 3501 visitConstantExpression(ConstantExpression.TRUE); 3502 3503 Label l1 = new Label(); 3504 cv.visitJumpInsn(GOTO, l1); 3505 cv.visitLabel(l0); 3506 3507 visitConstantExpression(ConstantExpression.FALSE); 3508 3509 cv.visitLabel(l1); 3510 } 3511 3512 protected void evaluateBinaryExpression(String method, BinaryExpression expression) { 3513 Expression leftExpression = expression.getLeftExpression(); 3514 leftHandExpression = false; 3515 leftExpression.visit(this); 3516 cv.visitLdcInsn(method); 3517 leftHandExpression = false; 3518 new ArgumentListExpression(new Expression[] { expression.getRightExpression()}).visit(this); 3519 invokeMethodMethod.call(cv); 3521 } 3522 3523 protected void evaluateCompareTo(BinaryExpression expression) { 3524 Expression leftExpression = expression.getLeftExpression(); 3525 leftHandExpression = false; 3526 leftExpression.visit(this); 3527 expression.getRightExpression().visit(this); 3528 compareToMethod.call(cv); 3529 } 3530 3531 protected void evaluateBinaryExpressionWithAsignment(String method, BinaryExpression expression) { 3532 Expression leftExpression = expression.getLeftExpression(); 3533 if (leftExpression instanceof BinaryExpression) { 3534 BinaryExpression leftBinExpr = (BinaryExpression) leftExpression; 3535 if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) { 3536 3542 MethodCallExpression methodCall = 3543 new MethodCallExpression( 3544 expression.getLeftExpression(), 3545 method, 3546 new ArgumentListExpression(new Expression[] { expression.getRightExpression()})); 3547 3548 Expression safeIndexExpr = createReusableExpression(leftBinExpr.getRightExpression()); 3549 3550 visitMethodCallExpression( 3551 new MethodCallExpression( 3552 leftBinExpr.getLeftExpression(), 3553 "putAt", 3554 new ArgumentListExpression(new Expression[] { safeIndexExpr, methodCall }))); 3555 return; 3557 } 3558 } 3559 3560 evaluateBinaryExpression(method, expression); 3561 3562 cv.visitInsn(DUP); 3564 3565 leftHandExpression = true; 3566 evaluateExpression(leftExpression); 3567 leftHandExpression = false; 3568 } 3569 3570 private void evaluateBinaryExpression(MethodCaller compareMethod, BinaryExpression bin) { 3571 if (ENABLE_EARLY_BINDING && true) { 3572 evalBinaryExp_EarlyBinding(compareMethod, bin); 3573 } 3574 else { 3575 evalBinaryExp_LateBinding(compareMethod, bin); 3576 } 3577 } 3578 3579 protected void evalBinaryExp_LateBinding(MethodCaller compareMethod, BinaryExpression expression) { 3580 Expression leftExp = expression.getLeftExpression(); 3581 Expression rightExp = expression.getRightExpression(); 3582 load(leftExp); 3583 load(rightExp); 3584 compareMethod.call(cv); 3585 } 3586 3587 3593 protected void evalBinaryExp_EarlyBinding(MethodCaller compareMethod, BinaryExpression expression) { 3594 Expression leftExp = expression.getLeftExpression(); 3595 Expression rightExp = expression.getRightExpression(); 3596 3597 expression.resolve(this); 3598 if (expression.isResolveFailed() || expression.getTypeClass() == null){ 3599 evalBinaryExp_LateBinding(compareMethod, expression); 3600 return; 3601 } 3602 else { 3603 Class lclass = leftExp.getTypeClass(); 3604 Class rclass = rightExp.getTypeClass(); 3605 if (lclass == null || rclass == null) { 3606 if ((lclass == null && rclass != null) || (lclass != null && rclass == null)) { 3607 if (leftExp == ConstantExpression.NULL && !rclass.isPrimitive() || 3609 rightExp == ConstantExpression.NULL && !lclass.isPrimitive()) { 3610 Expression exp = leftExp == ConstantExpression.NULL? rightExp : leftExp; 3611 int type = expression.getOperation().getType(); 3612 switch (type) { 3613 case Types.COMPARE_EQUAL : 3614 load(exp); 3615 cv.visitInsn(ICONST_1); 3616 cv.visitInsn(SWAP); 3617 Label l1 = new Label(); 3618 cv.visitJumpInsn(IFNULL, l1); 3619 cv.visitInsn(POP); 3620 cv.visitInsn(ICONST_0); 3621 cv.visitLabel(l1); 3622 return; 3623 case Types.COMPARE_NOT_EQUAL : 3624 load(exp); 3625 cv.visitInsn(ICONST_1); 3626 cv.visitInsn(SWAP); 3627 Label l2 = new Label(); 3628 cv.visitJumpInsn(IFNONNULL, l2); 3629 cv.visitInsn(POP); 3630 cv.visitInsn(ICONST_0); 3631 cv.visitLabel(l2); 3632 return; 3633 default: 3634 evalBinaryExp_LateBinding(compareMethod, expression); 3635 return; 3636 } 3637 } 3638 else { 3639 evalBinaryExp_LateBinding(compareMethod, expression); 3640 return; 3641 } 3642 } 3643 else { 3644 evalBinaryExp_LateBinding(compareMethod, expression); 3645 return; 3646 } 3647 } 3648 else if (lclass == String .class && rclass == String .class) { 3649 int type = expression.getOperation().getType(); 3650 switch (type) { 3651 case Types.COMPARE_EQUAL : load(leftExp); cast(String .class); 3653 load(rightExp); cast(String .class); 3654 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z"); 3655 return; 3657 case Types.COMPARE_NOT_EQUAL : 3658 load(leftExp);cast(String .class); 3659 load(rightExp); cast(String .class); 3660 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z"); 3661 cv.visitInsn(ICONST_1); 3662 cv.visitInsn(IXOR); 3663 return; 3665 case Types.COMPARE_TO : 3666 load(leftExp);cast(String .class); 3667 load(rightExp); cast(String .class); 3668 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "compareTo", "(Ljava/lang/Object;)I"); 3669 helper.quickBoxIfNecessary(int.class); return; 3671 case Types.COMPARE_GREATER_THAN : 3672 case Types.COMPARE_GREATER_THAN_EQUAL : 3673 case Types.COMPARE_LESS_THAN : 3674 case Types.COMPARE_LESS_THAN_EQUAL : 3675 { 3676 int op; 3677 switch (type) { 3678 case Types.COMPARE_GREATER_THAN : 3679 op = IFLE; 3680 break; 3681 case Types.COMPARE_GREATER_THAN_EQUAL : 3682 op = IFLT; 3683 break; 3684 case Types.COMPARE_LESS_THAN : 3685 op = IFGE; 3686 break; 3687 case Types.COMPARE_LESS_THAN_EQUAL : 3688 op = IFGT; 3689 break; 3690 default: 3691 System.err.println("flow control error: should not be here. type: " + type); 3692 return; 3693 } 3694 load(leftExp);cast(String .class); 3695 load(rightExp); cast(String .class); 3696 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "compareTo", "(Ljava/lang/Object;)I"); 3697 3698 Label l4 = new Label(); 3700 cv.visitJumpInsn(op, l4); 3701 cv.visitInsn(ICONST_1); Label l5 = new Label(); 3704 cv.visitJumpInsn(GOTO, l5); 3705 cv.visitLabel(l4); 3706 cv.visitInsn(ICONST_0); cv.visitLabel(l5); 3708 } 3709 return; 3710 3711 default: 3712 evalBinaryExp_LateBinding(compareMethod, expression); 3713 return; 3714 } 3715 } 3716 else if (Integer .class == lclass && Integer .class == rclass) { 3717 int type = expression.getOperation().getType(); 3718 switch (type) { 3719 case Types.COMPARE_EQUAL : load(leftExp); cast(Integer .class); 3721 load(rightExp); 3722 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "equals", "(Ljava/lang/Object;)Z"); 3723 return; 3725 case Types.COMPARE_NOT_EQUAL : 3726 load(leftExp); cast(Integer .class); 3727 load(rightExp); 3728 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "equals", "(Ljava/lang/Object;)Z"); 3729 cv.visitInsn(ICONST_1); 3730 cv.visitInsn(IXOR); 3731 return; 3733 case Types.COMPARE_TO : 3734 load(leftExp); cast(Integer .class); 3735 load(rightExp); 3736 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "compareTo", "(Ljava/lang/Object;)I"); 3737 helper.quickBoxIfNecessary(int.class); 3738 return; 3739 case Types.COMPARE_GREATER_THAN : 3740 case Types.COMPARE_GREATER_THAN_EQUAL : 3741 case Types.COMPARE_LESS_THAN : 3742 case Types.COMPARE_LESS_THAN_EQUAL : 3743 { 3744 int op; 3745 switch (type) { 3746 case Types.COMPARE_GREATER_THAN : 3747 op = IFLE; 3748 break; 3749 case Types.COMPARE_GREATER_THAN_EQUAL : 3750 op = IFLT; 3751 break; 3752 case Types.COMPARE_LESS_THAN : 3753 op = IFGE; 3754 break; 3755 case Types.COMPARE_LESS_THAN_EQUAL : 3756 op = IFGT; 3757 break; 3758 default: 3759 System.err.println("flow control error: should not be here. type: " + type); 3760 return; 3761 } 3762 load(leftExp); cast(Integer .class); 3763 load(rightExp); 3764 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "compareTo", "(Ljava/lang/Object;)I"); 3765 3766 Label l4 = new Label(); 3767 cv.visitJumpInsn(op, l4); 3768 cv.visitInsn(ICONST_1); Label l5 = new Label(); 3770 cv.visitJumpInsn(GOTO, l5); 3771 cv.visitLabel(l4); 3772 cv.visitInsn(ICONST_0); cv.visitLabel(l5); 3774 } 3775 return; 3776 3777 default: 3778 evalBinaryExp_LateBinding(compareMethod, expression); 3779 return; 3780 } 3781 } 3782 else { 3783 evalBinaryExp_LateBinding(compareMethod, expression); 3784 return; 3785 } 3786 } 3787 } 3788 3789 private void cast(Class aClass) { 3790 if (!aClass.isPrimitive() && aClass != Object .class) { 3791 cv.visitTypeInsn(CHECKCAST, BytecodeHelper.getClassInternalName(aClass.getName())); 3792 } 3793 } 3794 3795 protected void evaluateEqual(BinaryExpression expression) { 3796 if (ENABLE_EARLY_BINDING) { 3797 expression.resolve(this); 3798 if (expression.isTypeResolved()) { 3799 if (expression.getRightExpression().getTypeClass() == Void.TYPE) { 3800 throwException("void value appeared on right hand side of assignment. "); 3801 } 3802 } 3803 } 3804 3805 Expression leftExpression = expression.getLeftExpression(); 3806 if (leftExpression instanceof BinaryExpression) { 3807 BinaryExpression leftBinExpr = (BinaryExpression) leftExpression; 3808 if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) { 3809 do { 3815 if (true && ENABLE_EARLY_BINDING){ 3816 Class typeclass = leftBinExpr.getLeftExpression().getTypeClass(); 3817 if (typeclass == null) { 3818 break; 3819 } 3820 3821 if (typeclass == Map.class) { load(expression.getRightExpression()); 3823 cv.visitInsn(DUP); 3825 final Variable rightTemp = storeInTemp("rightTemp", expression.getRightExpression().getType()); 3826 final Class rclass = expression.getRightExpression().getTypeClass(); 3828 BytecodeExpression loadTempByteCode = new BytecodeExpression() { 3829 public void visit(GroovyCodeVisitor visitor) { 3830 cv.visitVarInsn(ALOAD, rightTemp.getIndex()); 3831 } 3832 protected void resolveType(AsmClassGenerator2 resolver) { 3833 setTypeClass(rclass); 3834 } 3835 }; 3836 3837 visitMethodCallExpression( 3838 new MethodCallExpression( 3839 leftBinExpr.getLeftExpression(), 3840 "put", 3841 new ArgumentListExpression( 3842 new Expression[] { 3843 leftBinExpr.getRightExpression(), 3844 loadTempByteCode}))); 3845 cv.visitInsn(POP); removeVar(rightTemp); 3847 return; 3848 } 3849 else if (typeclass == List.class){ 3850 3854 load(expression.getRightExpression()); 3855 cv.visitInsn(DUP); 3857 final Variable rightTemp = storeInTemp("rightTemp", expression.getRightExpression().getType()); 3858 final Class rclass = expression.getRightExpression().getTypeClass(); 3860 BytecodeExpression loadTempBytes = new BytecodeExpression() { 3861 public void visit(GroovyCodeVisitor visitor) { 3862 cv.visitVarInsn(ALOAD, rightTemp.getIndex()); 3863 } 3864 protected void resolveType(AsmClassGenerator2 resolver) { 3865 setTypeClass(rclass); 3866 } 3867 }; 3868 3869 visitMethodCallExpression( 3870 new MethodCallExpression( 3871 new ClassExpression(DefaultGroovyMethods.class), 3872 "putAt", 3873 new ArgumentListExpression( 3874 new Expression[] { 3875 leftBinExpr.getLeftExpression(), 3876 leftBinExpr.getRightExpression(), 3877 loadTempBytes }))); 3878 removeVar(rightTemp); 3879 return; 3880 3881 } 3882 else { 3883 break; 3884 } 3885 } 3886 } while (false); 3887 3888 visitMethodCallExpression( 3889 new MethodCallExpression( 3890 leftBinExpr.getLeftExpression(), 3891 "putAt", 3892 new ArgumentListExpression( 3893 new Expression[] { leftBinExpr.getRightExpression(), expression.getRightExpression()}))); 3894 return; 3896 } 3897 } 3898 3899 leftHandExpression = false; 3901 Expression rightExpression = expression.getRightExpression(); 3902 3903 String type = getLHSType(leftExpression); 3904 if (type != null) { 3905 3908 if (BytecodeHelper.isPrimitiveType(type)) { 3910 rightExpression.visit(this); 3911 } 3912 else { 3913 if (ENABLE_EARLY_BINDING) { 3914 if (leftExpression.isDynamic()) { visitAndAutoboxBoolean(rightExpression); 3916 } 3917 else { 3918 if (type.equals(rightExpression.getType())) { 3919 visitAndAutoboxBoolean(rightExpression); 3920 } 3921 else { 3922 if (rightExpression instanceof ConstantExpression && 3923 ((ConstantExpression)rightExpression).getValue() == null) { 3924 cv.visitInsn(ACONST_NULL); 3925 } 3926 else { 3927 visitCastExpression(new CastExpression(type, rightExpression)); 3928 } 3929 } 3930 } 3931 } 3932 else if (!type.equals("java.lang.Object")){ 3933 visitCastExpression(new CastExpression(type, rightExpression)); 3934 } 3935 else { 3936 visitAndAutoboxBoolean(rightExpression); 3937 } 3938 } 3939 } 3940 else { 3941 visitAndAutoboxBoolean(rightExpression); 3942 } 3943 3944 3945 if (ENABLE_EARLY_BINDING) { 3947 Class rc = rightExpression.getTypeClass(); 3948 if (rc != null && rc.isArray()) { 3949 Class elemType = rc.getComponentType(); 3950 if (elemType.isPrimitive()) { 3951 visitClassExpression(new ClassExpression(elemType)); 3952 convertPrimitiveArray.call(cv); 3953 cast(loadClass(BytecodeHelper.getObjectArrayTypeForPrimitiveArray(elemType.getName() + "[]"))); 3954 } 3955 } 3956 3957 3958 if (leftExpression.isDynamic() ) { 3959 if (!(leftExpression instanceof FieldExpression ) && !(leftExpression instanceof PropertyExpression)) 3961 copyTypeClass(leftExpression, rightExpression); 3962 } 3963 else { 3964 Class lc = leftExpression.getTypeClass(); 3965 if (lc != null && rc != null && !lc.isAssignableFrom(rc) && !lc.isPrimitive()) { 3967 if (!lc.isArray()) { 3969 visitClassExpression(new ClassExpression(lc)); 3970 asTypeMethod.call(cv); 3971 helper.doCast(lc); 3972 } 3973 else { 3974 Class elemType = lc.getComponentType(); 3976 if (elemType.isPrimitive()) { 3977 copyTypeClass(leftExpression, rightExpression); 3979 } 3980 } 3981 } 3982 } 3983 } 3984 cv.visitInsn(DUP); leftHandExpression = true; 3986 leftExpression.visit(this); 3987 leftHandExpression = false; 3988 } 3989 3990 private void copyTypeClass(Expression leftExpression, Expression rightExpression) { 3991 Class rclass = rightExpression.getTypeClass(); 3993 if (rightExpression instanceof ClassExpression) { 3994 leftExpression.setTypeClass(Class .class); 3995 } 3996 else { 3997 rclass = BytecodeHelper.boxOnPrimitive(rclass); 3998 leftExpression.setTypeClass(rclass); 3999 } 4000 } 4001 4002 private boolean canBeAssignedFrom(String ltype, String rtype) { 4003 if (rtype == null) { 4004 return false; 4005 } 4006 else if (ltype == null || ltype.equals("java.lang.Object")) { 4007 return true; 4008 } else { 4009 return false; 4010 } 4011 } 4012 4013 private boolean canBeAssignedFrom(Expression l, Expression r) { 4014 if (r.getTypeClass() == null) { 4015 return false; 4016 } 4017 else if (l.isDynamic()){ 4018 return true; 4019 } else { 4020 return false; 4021 } 4022 } 4023 private boolean canBeAssignedFrom(Class l, Class r) { 4024 if (r == null) { 4025 return false; 4026 } 4027 else if (l == null || l == Object .class){ 4028 return true; 4029 } else { 4030 return false; 4031 } 4032 } 4033 4034 4039 protected String getLHSType(Expression leftExpression) { 4040 do { 4041 } while (false); 4051 4052 if (leftExpression instanceof VariableExpression) { 4053 VariableExpression varExp = (VariableExpression) leftExpression; 4054 String type = varExp.getType(); 4055 if (isValidTypeForCast(type)) { 4056 return type; 4057 } 4058 String variableName = varExp.getVariable(); 4059 Variable variable = (Variable) variableStack.get(variableName); 4060 if (variable != null) { 4061 if (variable.isHolder() || variable.isProperty()) { 4062 return null; 4063 } 4064 type = variable.getTypeName(); 4065 if (isValidTypeForCast(type)) { 4066 return type; 4067 } 4068 } 4069 else { 4070 FieldNode field = classNode.getField(variableName); 4071 if (field == null) { 4072 field = classNode.getOuterField(variableName); 4073 } 4074 if (field != null) { 4075 type = field.getType(); 4076 if (!field.isHolder() && isValidTypeForCast(type)) { 4077 return type; 4078 } 4079 } 4080 } 4081 } 4082 return null; 4083 } 4084 4085 protected boolean isValidTypeForCast(String type) { 4086 return type != null && !type.equals("java.lang.Object") && !type.equals("groovy.lang.Reference") && !BytecodeHelper.isPrimitiveType(type); 4087 } 4088 4089 protected void visitAndAutoboxBoolean(Expression expression) { 4090 expression.visit(this); 4091 4092 if (isComparisonExpression(expression)) { 4093 helper.boxBoolean(); } 4095 } 4096 4097 protected void evaluatePrefixMethod(String method, Expression expression) { 4098 if (isNonStaticField(expression) && ! isHolderVariable(expression) && !isStaticMethod()) { 4099 cv.visitVarInsn(ALOAD, 0); 4100 } 4101 expression.visit(this); 4102 cv.visitLdcInsn(method); 4103 invokeNoArgumentsMethod.call(cv); 4104 4105 leftHandExpression = true; 4106 expression.visit(this); 4107 leftHandExpression = false; 4108 expression.visit(this); 4109 } 4110 4111 protected void evaluatePostfixMethod(String method, Expression expression) { 4112 leftHandExpression = false; 4113 expression.visit(this); 4114 4115 Variable tv = visitASTOREInTemp("postfix_" + method); 4116 int tempIdx = tv.getIndex(); 4117 cv.visitVarInsn(ALOAD, tempIdx); 4118 4119 cv.visitLdcInsn(method); 4120 invokeNoArgumentsMethod.call(cv); 4121 4122 store(expression); 4123 4124 cv.visitVarInsn(ALOAD, tempIdx); 4125 removeVar(tv); 4126 } 4127 4128 protected boolean isHolderVariable(Expression expression) { 4129 if (expression instanceof FieldExpression) { 4130 FieldExpression fieldExp = (FieldExpression) expression; 4131 return fieldExp.getField().isHolder(); 4132 } 4133 if (expression instanceof VariableExpression) { 4134 VariableExpression varExp = (VariableExpression) expression; 4135 Variable variable = (Variable) variableStack.get(varExp.getVariable()); 4136 if (variable != null) { 4137 return variable.isHolder(); 4138 } 4139 FieldNode field = classNode.getField(varExp.getVariable()); 4140 if (field != null) { 4141 return field.isHolder(); 4142 } 4143 } 4144 return false; 4145 } 4146 4147 protected void evaluateInstanceof(BinaryExpression expression) { 4148 expression.getLeftExpression().visit(this); 4149 Expression rightExp = expression.getRightExpression(); 4150 String className = null; 4151 if (rightExp instanceof ClassExpression) { 4152 ClassExpression classExp = (ClassExpression) rightExp; 4153 className = classExp.getType(); 4154 } 4155 else { 4156 throw new RuntimeException ( 4157 "Right hand side of the instanceof keyworld must be a class name, not: " + rightExp); 4158 } 4159 className = checkValidType(className, expression, "Must be a valid type name for an instanceof statement"); 4160 String classInternalName = BytecodeHelper.getClassInternalName(className); 4161 cv.visitTypeInsn(INSTANCEOF, classInternalName); 4162 } 4163 4164 4169 protected boolean argumentsUseStack(Expression arguments) { 4170 return arguments instanceof TupleExpression || arguments instanceof ClosureExpression; 4171 } 4172 4173 4176 protected boolean isNonStaticField(Expression expression) { 4177 FieldNode field = null; 4178 if (expression instanceof VariableExpression) { 4179 VariableExpression varExp = (VariableExpression) expression; 4180 field = classNode.getField(varExp.getVariable()); 4181 } 4182 else if (expression instanceof FieldExpression) { 4183 FieldExpression fieldExp = (FieldExpression) expression; 4184 field = classNode.getField(fieldExp.getFieldName()); 4185 } 4186 else if (expression instanceof PropertyExpression) { 4187 PropertyExpression fieldExp = (PropertyExpression) expression; 4188 field = classNode.getField(fieldExp.getProperty()); 4189 } 4190 if (field != null) { 4191 return !field.isStatic(); 4192 } 4193 return false; 4194 } 4195 4196 protected boolean isThisExpression(Expression expression) { 4197 if (expression instanceof VariableExpression) { 4198 VariableExpression varExp = (VariableExpression) expression; 4199 return varExp.getVariable().equals("this"); 4200 } 4201 return false; 4202 } 4203 4204 4208 protected Expression createReturnLHSExpression(Expression expression) { 4209 if (expression instanceof BinaryExpression) { 4210 BinaryExpression binExpr = (BinaryExpression) expression; 4211 if (binExpr.getOperation().isA(Types.ASSIGNMENT_OPERATOR)) { 4212 return createReusableExpression(binExpr.getLeftExpression()); 4213 } 4214 } 4215 return null; 4216 } 4217 4218 protected Expression createReusableExpression(Expression expression) { 4219 ExpressionTransformer transformer = new ExpressionTransformer() { 4220 public Expression transform(Expression expression) { 4221 if (expression instanceof PostfixExpression) { 4222 PostfixExpression postfixExp = (PostfixExpression) expression; 4223 return postfixExp.getExpression(); 4224 } 4225 else if (expression instanceof PrefixExpression) { 4226 PrefixExpression prefixExp = (PrefixExpression) expression; 4227 return prefixExp.getExpression(); 4228 } 4229 return expression; 4230 } 4231 }; 4232 4233 return transformer.transform(expression.transformExpression(transformer)); 4235 } 4236 4237 protected boolean isComparisonExpression(Expression expression) { 4238 if (expression instanceof BinaryExpression) { 4239 BinaryExpression binExpr = (BinaryExpression) expression; 4240 switch (binExpr.getOperation().getType()) { 4241 case Types.COMPARE_EQUAL : 4242 case Types.MATCH_REGEX : 4243 case Types.COMPARE_GREATER_THAN : 4244 case Types.COMPARE_GREATER_THAN_EQUAL : 4245 case Types.COMPARE_LESS_THAN : 4246 case Types.COMPARE_LESS_THAN_EQUAL : 4247 case Types.COMPARE_IDENTICAL : 4248 case Types.COMPARE_NOT_EQUAL : 4249 case Types.KEYWORD_INSTANCEOF : 4250 return true; 4251 } 4252 } 4253 else if (expression instanceof BooleanExpression) { 4254 return true; 4255 } 4256 return false; 4257 } 4258 4259 protected void onLineNumber(ASTNode statement, String message) { 4260 int line = statement.getLineNumber(); 4261 int col = statement.getColumnNumber(); 4262 this.currentASTNode = statement; 4263 4264 if (line >=0) { 4265 lineNumber = line; 4266 columnNumber = col; 4267 } 4268 if (CREATE_DEBUG_INFO && line >= 0 && cv != null) { 4269 Label l = new Label(); 4270 cv.visitLabel(l); 4271 cv.visitLineNumber(line, l); 4272 if (ASM_DEBUG) { 4273 helper.mark(message + "[" + statement.getLineNumber() + ":" + statement.getColumnNumber() + "]"); 4274 } 4275 } 4276 } 4277 4278 protected VariableScope getVariableScope() { 4279 if (variableScope == null) { 4280 if (methodNode != null) { 4281 variableScope = methodNode.getVariableScope(); 4283 if (variableScope == null) { 4284 variableScope = new VariableScope(); 4285 methodNode.setVariableScope(variableScope); 4286 VariableScopeCodeVisitor visitor = new VariableScopeCodeVisitor(variableScope); 4287 visitor.setParameters(methodNode.getParameters()); 4288 Statement code = methodNode.getCode(); 4289 if (code != null) { 4290 code.visit(visitor); 4291 } 4292 } 4293 addFieldsToVisitor(variableScope); 4294 } 4295 else if (constructorNode != null) { 4296 variableScope = new VariableScope(); 4297 constructorNode.setVariableScope(variableScope); 4298 VariableScopeCodeVisitor visitor = new VariableScopeCodeVisitor(variableScope); 4299 visitor.setParameters(constructorNode.getParameters()); 4300 Statement code = constructorNode.getCode(); 4301 if (code != null) { 4302 code.visit(visitor); 4303 } 4304 addFieldsToVisitor(variableScope); 4305 } 4306 else { 4307 throw new RuntimeException ("Can't create a variable scope outside of a method or constructor"); 4308 } 4309 } 4310 return variableScope; 4311 } 4312 4313 4317 protected Parameter[] getClosureSharedVariables(ClosureExpression expression) { 4318 List vars = new ArrayList(); 4319 4320 4325 VariableScope outerScope = getVariableScope().createRecursiveParentScope(); 4326 VariableScope innerScope = expression.getVariableScope(); 4327 if (innerScope == null) { 4328 System.out.println( 4329 "No variable scope for: " + expression + " method: " + methodNode + " constructor: " + constructorNode); 4330 innerScope = new VariableScope(getVariableScope()); 4331 } 4332 else { 4333 innerScope = innerScope.createRecursiveChildScope(); 4334 } 4335 4336 4337 4346 Set outerDecls = outerScope.getDeclaredVariables(); 4347 Set outerRefs = outerScope.getReferencedVariables(); 4348 Set innerDecls = innerScope.getDeclaredVariables(); 4349 Set innerRefs = innerScope.getReferencedVariables(); 4350 4351 4352 4366 Set varSet = new HashSet(); 4367 for (Iterator iter = innerRefs.iterator(); iter.hasNext();) { 4368 String var = (String ) iter.next(); 4369 if (outerDecls.contains(var) && (isNotFieldOfOutermostClass(var))) { 4371 String type = getVariableType(var); 4372 vars.add(new Parameter(type, var)); 4373 varSet.add(var); 4374 } 4375 } 4376 for (Iterator iter = outerRefs.iterator(); iter.hasNext();) { 4377 String var = (String ) iter.next(); 4378 if (innerDecls.contains(var) && (isNotFieldOfOutermostClass(var)) && !varSet.contains(var)) { 4380 String type = getVariableType(var); 4381 vars.add(new Parameter(type, var)); 4382 } 4383 } 4384 4385 4386 Parameter[] answer = new Parameter[vars.size()]; 4387 vars.toArray(answer); 4388 return answer; 4389 } 4390 4391 protected boolean isNotFieldOfOutermostClass(String var) { 4392 return getOutermostClass().getField(var) == null; 4394 } 4395 4396 protected void findMutableVariables() { 4397 4405 VariableScope outerScope = getVariableScope(); 4406 4407 VariableScope innerScope = outerScope.createCompositeChildScope(); 4409 4410 Set outerDecls = outerScope.getDeclaredVariables(); 4411 Set outerRefs = outerScope.getReferencedVariables(); 4412 Set innerDecls = innerScope.getDeclaredVariables(); 4413 Set innerRefs = innerScope.getReferencedVariables(); 4414 4415 mutableVars.clear(); 4416 4417 for (Iterator iter = innerDecls.iterator(); iter.hasNext();) { 4418 String var = (String ) iter.next(); 4419 if ((outerDecls.contains(var) || outerRefs.contains(var)) && classNode.getField(var) == null) { 4420 mutableVars.add(var); 4421 } 4422 } 4423 4424 for (Iterator iter = innerRefs.iterator(); iter.hasNext();) { 4427 String var = (String ) iter.next(); 4428 if (outerDecls.contains(var) && classNode.getField(var) == null) { 4429 mutableVars.add(var); 4430 } 4431 } 4432 4433 } 4441 4442 protected void addFieldsToVisitor(VariableScope scope) { 4443 for (Iterator iter = classNode.getFields().iterator(); iter.hasNext();) { 4444 FieldNode field = (FieldNode) iter.next(); 4445 String name = field.getName(); 4446 4447 scope.getDeclaredVariables().add(name); 4448 scope.getReferencedVariables().add(name); 4449 } 4450 } 4451 4452 private boolean isInnerClass() { 4453 return classNode instanceof InnerClassNode; 4454 } 4455 4456 protected String getVariableType(String name) { 4457 Variable variable = (Variable) variableStack.get(name); 4458 if (variable != null) { 4459 return variable.getTypeName(); 4460 } 4461 return null; 4462 } 4463 4464 protected void resetVariableStack(Parameter[] parameters) { 4465 lastVariableIndex = -1; 4466 variableStack.clear(); 4467 4468 scope = new BlockScope(null); 4469 4471 definingParameters = true; 4473 if (!isStaticMethod()) { 4474 defineVariable("this", classNode.getName()).getIndex(); 4475 } for (int i = 0; i < parameters.length; i++) { 4477 Parameter parameter = parameters[i]; 4478 String type = parameter.getType(); 4479 Variable v = defineVariable(parameter.getName(), type); 4480 int idx = v.getIndex(); 4481 if (BytecodeHelper.isPrimitiveType(type)) { 4482 helper.load(type, idx); 4483 helper.box(type); 4484 cv.visitVarInsn(ASTORE, idx); 4485 } 4486 } 4487 definingParameters = false; 4488 } 4489 4490 protected void popScope() { 4491 int lastID = scope.getFirstVariableIndex(); 4492 4493 List removeKeys = new ArrayList(); 4494 for (Iterator iter = variableStack.entrySet().iterator(); iter.hasNext();) { 4495 Map.Entry entry = (Map.Entry) iter.next(); 4496 String name = (String ) entry.getKey(); 4497 Variable value = (Variable) entry.getValue(); 4498 if (value.getIndex() >= lastID) { 4499 removeKeys.add(name); 4500 } 4501 } 4502 for (Iterator iter = removeKeys.iterator(); iter.hasNext();) { 4503 Variable v = (Variable) variableStack.remove(iter.next()); 4504 if (CREATE_DEBUG_INFO) { if (v != null) { 4506 visitVariableEndLabel(v); 4507 cv.visitLocalVariable( 4508 v.getName(), 4509 BytecodeHelper.getTypeDescription(v.getTypeName()), 4510 v.getStartLabel(), 4511 v.getEndLabel(), 4512 v.getIndex() 4513 ); 4514 } 4515 } 4516 } 4517 scope = scope.getParent(); 4518 } 4519 4520 void removeVar(Variable v ) { 4521 variableStack.remove(v.getName()); 4522 if (CREATE_DEBUG_INFO) { Label endl = new Label(); 4524 cv.visitLabel(endl); 4525 cv.visitLocalVariable( 4526 v.getName(), 4527 BytecodeHelper.getTypeDescription(v.getTypeName()), 4528 v.getStartLabel(), 4529 endl, 4530 v.getIndex() 4531 ); 4532 } 4533 } 4534 private void visitVariableEndLabel(Variable v) { 4535 if (CREATE_DEBUG_INFO) { 4536 if(v.getEndLabel() == null) { 4537 Label end = new Label(); 4538 v.setEndLabel(end); 4539 } 4540 cv.visitLabel(v.getEndLabel()); 4541 } 4542 } 4543 4544 protected void pushBlockScope() { 4545 pushBlockScope(true, true); 4546 } 4547 4548 4554 protected void pushBlockScope(boolean canContinue, boolean canBreak) { 4555 BlockScope parentScope = scope; 4556 scope = new BlockScope(parentScope); 4557 scope.setContinueLabel(canContinue ? new Label() : (parentScope == null ? null : parentScope.getContinueLabel())); 4558 scope.setBreakLabel(canBreak? new Label() : (parentScope == null ? null : parentScope.getBreakLabel())); 4559 scope.setFirstVariableIndex(getNextVariableID()); 4560 } 4561 4562 4565 protected Variable defineVariable(String name, String type) { 4566 return defineVariable(name, type, true); 4567 } 4568 4569 protected Variable defineVariable(String name, String type, boolean define) { 4570 return defineVariable(name, new Type(type), define); 4571 } 4572 4573 private Variable defineVariable(String name, Type type, boolean define) { 4574 Variable answer = (Variable) variableStack.get(name); 4575 if (answer == null) { 4576 lastVariableIndex = getNextVariableID(); 4577 answer = new Variable(lastVariableIndex, type, name); 4578 if (mutableVars.contains(name)) { 4579 answer.setHolder(true); 4580 } 4581 variableStack.put(name, answer); 4582 Label startLabel = new Label(); 4583 answer.setStartLabel(startLabel); 4584 if (define) { 4585 if (definingParameters) { 4586 if (answer.isHolder()) { 4587 cv.visitTypeInsn(NEW, "groovy/lang/Reference"); cv.visitInsn(DUP); 4589 cv.visitVarInsn(ALOAD, lastVariableIndex); 4590 cv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "(Ljava/lang/Object;)V"); 4591 cv.visitVarInsn(ASTORE, lastVariableIndex); 4592 cv.visitLabel(startLabel); 4593 } 4594 } 4595 else { 4596 if (answer.isHolder() && !isInScriptBody()) { 4599 4601 cv.visitTypeInsn(NEW, "groovy/lang/Reference"); 4602 cv.visitInsn(DUP); 4603 cv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "()V"); 4604 4605 cv.visitVarInsn(ASTORE, lastVariableIndex); 4606 cv.visitLabel(startLabel); 4607 } 4609 else { 4610 if (!leftHandExpression) { cv.visitInsn(ACONST_NULL); 4612 cv.visitVarInsn(ASTORE, lastVariableIndex); 4613 cv.visitLabel(startLabel); 4614 } 4615 } 4616 } 4617 } 4618 } 4619 return answer; 4620 } 4621 4622 private int getNextVariableID() { 4623 return variableStack.size(); } 4626 4627 4628 protected boolean isFieldOrVariable(String name) { 4629 return variableStack.containsKey(name) || classNode.getField(name) != null; 4630 } 4631 4632 protected Type checkValidType(Type type, ASTNode node, String message) { 4633 if (type.isDynamic()) { 4634 return type; 4635 } 4636 String name = checkValidType(type.getName(), node, message); 4637 if (type.getName().equals(name)) { 4638 return type; 4639 } 4640 return new Type(name); 4641 } 4642 4643 protected String checkValidType(String type, ASTNode node, String message) { 4644 if (type!= null && type.length() == 0) 4645 return "java.lang.Object"; 4646 if (type.endsWith("[]")) { 4647 String postfix = "[]"; 4648 String prefix = type.substring(0, type.length() - 2); 4649 return checkValidType(prefix, node, message) + postfix; 4650 } 4651 int idx = type.indexOf('$'); 4652 if (idx > 0) { 4653 String postfix = type.substring(idx); 4654 String prefix = type.substring(0, idx); 4655 return checkValidType(prefix, node, message) + postfix; 4656 } 4657 if (BytecodeHelper.isPrimitiveType(type) || "void".equals(type)) { 4658 return type; 4659 } 4660 String original = type; 4661 type = resolveClassName(type); 4662 if (type != null) { 4663 return type; 4664 } 4665 4666 throw new MissingClassException(original, node, message + " for class: " + classNode.getName()); 4667 } 4668 4669 protected String resolveClassName(String type) { 4670 return classNode.resolveClassName(type); 4671 } 4672 4673 protected String createVariableName(String type) { 4674 return "__" + type + (++tempVariableNameCounter); 4675 } 4676 4677 4681 protected String getExpressionType(Expression expression) { 4682 if (isComparisonExpression(expression)) { 4683 return "boolean"; 4684 } 4685 if (expression instanceof VariableExpression) { 4686 VariableExpression varExpr = (VariableExpression) expression; 4687 Variable variable = (Variable) variableStack.get(varExpr.getVariable()); 4688 if (variable != null && !variable.isHolder()) { 4689 Type type = variable.getType(); 4690 if (! type.isDynamic()) { 4691 return type.getName(); 4692 } 4693 } 4694 } 4695 return null; 4696 } 4697 4698 4702 protected static boolean isPrimitiveFieldType(String type) { 4703 return type.equals("java.lang.String") 4704 || type.equals("java.lang.Integer") 4705 || type.equals("java.lang.Double") 4706 || type.equals("java.lang.Long") 4707 || type.equals("java.lang.Float"); 4708 } 4709 4710 protected boolean isInClosureConstructor() { 4711 return constructorNode != null 4712 && classNode.getOuterClass() != null 4713 && classNode.getSuperClass().equals(Closure.class.getName()); 4714 } 4715 4716 protected boolean isStaticMethod() { 4717 if (methodNode == null) { return false; 4719 } 4720 return methodNode.isStatic(); 4721 } 4722 4723 Map classCache = new HashMap(); 4724 { 4725 classCache.put("int", Integer.TYPE); 4726 classCache.put("byte", Byte.TYPE); 4727 classCache.put("short", Short.TYPE); 4728 classCache.put("char", Character.TYPE); 4729 classCache.put("boolean", Boolean.TYPE); 4730 classCache.put("long", Long.TYPE); 4731 classCache.put("double", Double.TYPE); 4732 classCache.put("float", Float.TYPE); 4733 classCache.put("void", Void.TYPE); 4734 } 4735 4738 protected Class loadClass(String name) { 4739 4740 if (name.equals(this.classNode.getName())) { 4741 return Object .class; 4742 } 4743 4744 if (name == null) { 4745 return null; 4746 } 4747 else if (name.length() == 0) { 4748 return Object .class; 4749 } 4750 4751 name = BytecodeHelper.formatNameForClassLoading(name); 4752 4753 try { 4754 Class cls = (Class )classCache.get(name); 4755 if (cls != null) 4756 return cls; 4757 4758 CompileUnit compileUnit = getCompileUnit(); 4759 if (compileUnit != null) { 4760 cls = compileUnit.loadClass(name); 4761 classCache.put(name, cls); 4762 return cls; 4763 } 4764 else { 4765 throw new ClassGeneratorException("Could not load class: " + name); 4766 } 4767 } 4768 catch (ClassNotFoundException e) { 4769 throw new ClassGeneratorException("Error when compiling class: " + classNode.getName() + ". Reason: could not load class: " + name + " reason: " + e, e); 4770 } 4771 } 4772 4773 protected CompileUnit getCompileUnit() { 4774 CompileUnit answer = classNode.getCompileUnit(); 4775 if (answer == null) { 4776 answer = context.getCompileUnit(); 4777 } 4778 return answer; 4779 } 4780 4781 4785 public void resolve(MethodCallExpression call) { 4786 if (call.isResolveFailed()) { 4787 return; 4788 } 4789 else if (call.isTypeResolved()) { 4790 return; 4791 } 4792 4793 Expression obj = call.getObjectExpression(); 4794 String meth = call.getMethod(); 4795 Class ownerClass = null; 4796 boolean isStaticCall = false; 4797 boolean isSuperCall = false; 4798 4799 List arglist = new ArrayList(); 4800 Expression args = call.getArguments(); 4801 if (args instanceof TupleExpression) { 4802 TupleExpression tupleExpression = (TupleExpression) args; 4803 List argexps = tupleExpression.getExpressions(); 4804 for (int i = 0; i < argexps.size(); i++) { 4805 Expression expression = (Expression) argexps.get(i); 4806 Class cls = expression.getTypeClass(); 4807 if (cls == null) { 4808 call.setResolveFailed(true); 4809 return ; 4810 } 4811 else { 4812 arglist.add(cls); 4813 } 4814 } 4815 } else if (args instanceof ClosureExpression) { 4816 call.setResolveFailed(true); 4817 return ; } else { 4819 call.setResolveFailed(true); 4820 return ; 4821 } 4822 4823 4824 Class [] argsArray = new Class [arglist.size()]; 4825 arglist.toArray(argsArray); 4826 4827 4828 if (obj instanceof ClassExpression) { 4829 ownerClass = obj.getTypeClass(); isStaticCall = true; 4834 } else if (obj instanceof VariableExpression) { 4835 VariableExpression var = (VariableExpression) obj; 4836 if (var.getVariable().equals("this") && (methodNode == null? true : !methodNode.isStatic()) ) { 4837 isStaticCall = false; 4838 if (methodNode != null) { 4839 isStaticCall = Modifier.isStatic(methodNode.getModifiers()); 4840 } 4841 MetaMethod mmeth = getMethodOfThisAndSuper(meth, argsArray, isStaticCall); 4842 if (mmeth != null) { 4843 call.setMethod(mmeth); 4844 return ; 4845 } 4846 else { 4847 call.setResolveFailed(true); 4848 return ; 4849 } 4850 } 4851 else if (var.getVariable().equals("super") ) { 4852 isSuperCall = true; 4853 ownerClass = var.getTypeClass(); 4854 } 4855 else { 4856 ownerClass = var.getTypeClass(); 4857 } 4858 } 4859 else { 4860 ownerClass = obj.getTypeClass(); 4861 if (ownerClass == null) { 4862 call.setResolveFailed(true); 4863 call.setFailure("target class is null"); 4864 return ; } 4866 } 4867 4868 if (ownerClass == Object .class) { 4869 call.setResolveFailed(true); 4870 return ; } 4872 else if (ownerClass == null) { 4873 call.setResolveFailed(true); 4874 return ; } 4876 else 4877 if (!isSuperCall && !isStaticCall && GroovyObject.class.isAssignableFrom(ownerClass) ) { call.setResolveFailed(true); 4879 return ; 4880 } 4881 else 4882 if (ownerClass.isPrimitive()) { 4883 call.setResolveFailed(true); 4884 return ; } 4886 4887 4888 MetaMethod mmethod = MetaClassRegistry.getIntance(MetaClassRegistry.DONT_LOAD_DEFAULT).getDefinedMethod(ownerClass, meth, argsArray, isStaticCall); 4891 if (mmethod!= null) { 4892 call.setMethod(mmethod); 4893 } 4894 else { 4895 call.setResolveFailed(true); 4896 } 4897 return ; 4898 } 4899 4903 public void resolve(ConstructorCallExpression call) { 4904 if (call.isResolveFailed()) { 4905 return ; 4906 } 4907 else if (call.isTypeResolved()) { 4908 return ; 4909 } 4910 4911 String declaredType = call.getTypeToSet(); 4912 if (declaredType.equals(classNode.getName())) { 4913 call.setResolveFailed(true); 4914 call.setFailure("cannot resolve on the current class itself. "); 4915 return; 4916 } 4917 else { 4918 call.setType(declaredType); 4919 if (call.getTypeClass() == null) { 4920 call.setResolveFailed(true); 4921 call.setFailure("type name cannot be resolved. "); 4922 return; 4923 } 4924 } 4925 4926 boolean isSuperCall = false; 4927 4928 List arglist = new ArrayList(); 4929 Expression args = call.getArguments(); 4930 if (args instanceof TupleExpression) { 4931 TupleExpression tupleExpression = (TupleExpression) args; 4932 List argexps = tupleExpression.getExpressions(); 4933 for (int i = 0; i < argexps.size(); i++) { 4934 Expression expression = (Expression) argexps.get(i); 4935 Class cls = expression.getTypeClass(); 4936 if (cls == null) { 4937 call.setResolveFailed(true); 4938 return ; 4939 } 4940 else { 4941 arglist.add(cls); 4942 } 4943 } 4944 } else if (args instanceof ClosureExpression) { 4945 call.setResolveFailed(true); 4946 call.setFailure("don't know how to handle closure arg. "); 4947 return ; } else { 4949 call.setResolveFailed(true); 4950 call.setFailure("unknown arg type: " + args.getClass().getName()); 4951 return ; 4952 } 4953 4954 4955 Class [] argsArray = new Class [arglist.size()]; 4956 arglist.toArray(argsArray); 4957 4958 Class ownerClass = call.getTypeClass(); 4959 if (ownerClass == null) { 4960 String typeName = call.getType(); 4961 if (typeName.equals(this.classNode.getName())) { 4962 call.setResolveFailed(true); 4964 call.setFailure("invoke constructor for this. no optimization for now"); 4965 return ; 4966 } 4967 else { 4968 try { 4969 ownerClass = loadClass(typeName); 4970 if (ownerClass == null) { 4971 call.setResolveFailed(true); 4972 call.setFailure("owner class type is null. "); 4973 return ; 4974 } 4975 } 4976 catch (Throwable th) { 4977 call.setResolveFailed(true); 4978 call.setFailure("Exception: " + th); 4979 return ; 4980 } 4981 } 4982 } 4983 4984 if (ownerClass == Object .class) { 4985 call.setResolveFailed(true); 4986 call.setFailure("owner class type java.lang.Object. use late binding for dynamic types"); 4987 return ; } 4989 else if (ownerClass == null) { 4990 call.setResolveFailed(true); 4991 call.setFailure("owner class type is null. use dynamic dispatching for GroovyObject"); 4992 return; } 4994 else if (ownerClass.isPrimitive()) { 5000 call.setResolveFailed(true); 5001 throwException("The owner of the constructor is primitive."); 5002 return ; 5003 } 5004 5005 Constructor ctor = MetaClassRegistry.getIntance(MetaClassRegistry.DONT_LOAD_DEFAULT).getDefinedConstructor(ownerClass, argsArray); 5006 if (ctor!= null) { 5007 call.setConstructor(ctor); 5008 } 5009 else { 5010 call.setResolveFailed(true); 5011 } 5012 return ; 5013 } 5014 5015 public void resolve(PropertyExpression propertyExpression) { 5016 if (propertyExpression.getTypeClass() != null) 5017 return ; 5018 if (propertyExpression.isResolveFailed()) 5019 return ; 5020 5021 Expression ownerExp = propertyExpression.getObjectExpression(); 5022 Class ownerClass = ownerExp.getTypeClass(); 5023 String propName = propertyExpression.getProperty(); 5024 if (propName.equals("class")) { 5025 propertyExpression.setTypeClass(Class .class); 5026 return ; 5027 } 5028 5029 if (ownerClass != null && ownerClass.isArray() && propName.equals("length")) { 5031 propertyExpression.setTypeClass(int.class); 5032 return; 5033 } 5034 5035 if (isThisExpression(ownerExp)) { 5036 if (classNode == null) { 5038 propertyExpression.setResolveFailed(true); 5039 return ; 5040 } 5041 FieldNode field = null; 5042 ownerExp.setType(classNode.getName()); 5043 try { 5044 if( (field = classNode.getField(propName)) != null ) { 5045 propertyExpression.setResolveFailed(true); 5050 propertyExpression.setFailure("local property access. to be determined in the future."); 5051 return ; 5052 } else { 5053 String [] interfaces = classNode.getInterfaces(); 5056 String [] supers = new String [interfaces.length + 1]; 5057 5058 int i = 0; 5059 for (; i < interfaces.length; i++) { 5060 supers[i] = interfaces[i]; 5061 } 5062 supers[i] = classNode.getSuperClass(); 5063 for (int j = 0; j < supers.length; j++) { 5064 String aSuper = supers[j]; 5065 Class superClass = loadClass(aSuper); 5066 Field fld = superClass.getDeclaredField(propName); 5067 if (fld != null && !Modifier.isPrivate(fld.getModifiers())) { 5068 propertyExpression.setField(fld); 5069 return ; 5070 } 5071 } 5072 } 5073 } catch (Exception e) { 5074 propertyExpression.setResolveFailed(true); 5075 propertyExpression.setFailure(e.getMessage()); 5076 return ; 5077 } 5078 } 5079 else if (ownerExp instanceof ClassExpression) { 5080 if (ownerClass != null) { 5081 Field fld = null; 5082 try { 5083 fld = ownerClass.getDeclaredField(propName); 5084 if (!Modifier.isPrivate(fld.getModifiers())) { 5085 propertyExpression.setField(fld); 5086 return ; 5087 } 5088 } catch (NoSuchFieldException e) { 5089 propertyExpression.setResolveFailed(true); 5090 return ; 5091 } 5092 } 5093 } 5094 else { if (ownerClass != null) { 5096 propertyExpression.setResolveFailed(true); Field fld = null; 5098 try { 5099 fld = ownerClass.getDeclaredField(propName); 5100 } catch (NoSuchFieldException e) {} 5101 5102 if (fld != null && Modifier.isPublic(fld.getModifiers())) { 5103 propertyExpression.setField(fld); 5104 } 5105 5106 String getterName = "get" + Character.toUpperCase(propName.charAt(0)) + propName.substring(1); 5108 String setterName = "set" + Character.toUpperCase(propName.charAt(0)) + propName.substring(1); 5109 5110 Method [] meths = ownerClass.getMethods(); 5111 for (int i = 0; i < meths.length; i++) { 5112 Method method = meths[i]; 5113 String methName =method.getName(); 5114 Class [] paramClasses = method.getParameterTypes(); 5115 if (methName.equals(getterName) && paramClasses.length == 0) { 5116 propertyExpression.setGetter(method); 5117 } else if (methName.equals(setterName) && paramClasses.length == 1) { 5118 propertyExpression.setSetter(method); 5119 } 5120 } 5121 return ; 5122 } 5123 } 5124 propertyExpression.setResolveFailed(true); 5125 return ; 5126 } 5127 5128 private MetaMethod getMethodOfThisAndSuper(String methName, Class [] argsArray, boolean isStaticCall) { 5129 MethodNode candidate = null; 5130 List meths = classNode.getMethods(); 5131 Class [] candidateParamClasses = null; 5132 for (int i = 0; i < meths.size(); i++) { 5133 MethodNode meth = (MethodNode) meths.get(i); 5134 if (meth.getName().equals(methName)) { 5135 Parameter[] params = meth.getParameters(); 5136 if (params.length == argsArray.length) { 5137 Class [] paramClasses = new Class [params.length]; 5138 for (int j = 0; j < params.length; j++) { 5139 Parameter param = params[j]; 5140 String type = param.getType(); 5141 Class paramClass = null; 5142 try { 5143 paramClass = loadClass(type); 5144 } catch (Exception e) { 5145 log.warning(e.getMessage()); 5146 return null; 5147 } 5148 paramClasses[j] = paramClass; 5149 } 5150 if (MetaClass.isValidMethod(paramClasses, argsArray, false)) { 5151 candidateParamClasses = paramClasses; 5152 candidate = meth; 5153 break; 5154 } 5155 else { 5156 if (MetaClass.isValidMethod(paramClasses, argsArray, true)){ 5157 candidateParamClasses = paramClasses; 5158 candidate = meth; 5159 break; 5160 } 5161 } 5162 } 5163 } 5164 } 5165 5166 if (candidate != null && candidateParamClasses != null) { 5167 try { 5169 return new MetaMethod(methName, null, candidateParamClasses, loadClass(candidate.getReturnType()), candidate.getModifiers()); 5170 } catch (Exception e) { 5171 log.warning(e.getMessage()); 5172 return null; 5173 } 5174 } 5175 else { 5176 Class superClass = null; 5178 try { 5179 superClass = loadClass(classNode.getSuperClass()); 5180 } 5181 catch(Exception e) { 5182 log.warning(e.getMessage()); 5184 } 5185 if (superClass != null ) { 5187 MetaMethod mmethod = MetaClassRegistry.getIntance(MetaClassRegistry.DONT_LOAD_DEFAULT).getDefinedMethod(superClass, methName, argsArray, isStaticCall); 5188 if (mmethod == null) 5189 return null; 5190 int modies = mmethod.getModifiers(); 5191 if (Modifier.isPrivate(modies)) { 5192 return null; 5193 } 5194 else if(modies == 0) { 5195 int pThis = classNode.getName().lastIndexOf("."); 5197 String packageNameThis = pThis > 0? classNode.getName().substring(0, pThis) : ""; 5198 5199 int pSuper = classNode.getSuperClass().lastIndexOf("."); 5200 String packageNameSuper = pSuper > 0? classNode.getSuperClass().substring(0, pSuper) : ""; 5201 if (packageNameThis.equals(packageNameSuper)) { 5202 return new MetaMethod(methName, null, mmethod.getParameterTypes(), mmethod.getReturnType(), mmethod.getModifiers()); 5203 } 5204 else { 5205 return null; 5206 } 5207 } 5208 else { 5209 return new MetaMethod(methName, null, mmethod.getParameterTypes(), mmethod.getReturnType(), mmethod.getModifiers()); 5211 } 5212 } 5213 return null; 5214 } 5215 } 5216 5217 5218 5221 public void resolve(VariableExpression expression) { 5222 5223 String variableName = expression.getVariable(); 5224 5228 5231 if (isStaticMethod() && variableName.equals("this")) { 5232 expression.setTypeClass(Class .class); 5233 return; 5234 } else if (variableName.equals("super")) { 5235 if (isStaticMethod() ) { 5236 expression.setTypeClass(Class .class); 5237 return; 5238 } 5239 else { 5240 try { 5241 Class cls = loadClass(classNode.getSuperClass()); 5242 expression.setTypeClass(cls); 5243 return ; 5244 } 5245 catch (Exception e) { 5246 expression.setResolveFailed(true); 5247 expression.setFailure(e.getMessage()); 5248 return ; 5249 } 5250 } 5251 } else if (variableName.equals("this")){ 5252 return ; 5253 } else { 5254 } 5259 5260 5261 5264 5272 boolean handled = false; 5273 Variable variable = (Variable)variableStack.get( variableName ); 5274 5275 try { 5276 if( variable != null ) { 5277 Type t = variable.getType(); 5278 if (t.getRealName().length() == 0) { 5279 String tname = t.getName(); 5280 if (tname.endsWith("[]")) { 5281 expression.setResolveFailed(true); 5282 expression.setFailure("array type to be supported later"); 5283 return ; } 5285 else if (tname.equals(classNode.getName())){ 5286 expression.setResolveFailed(true); 5287 return ; 5288 } 5289 else if (classNode.getOuterClass() != null && tname.equals(classNode.getOuterClass().getName())){ 5290 expression.setResolveFailed(true); 5291 return ; 5292 } 5293 Class cls = loadClass(tname); 5294 expression.setTypeClass(cls); 5295 expression.setDynamic(t.isDynamic()); 5296 return ; 5297 } else { 5298 String tname = t.getRealName(); 5299 if (tname.endsWith("[]")) { 5300 expression.setResolveFailed(true); 5301 expression.setFailure("array type to be supported later"); 5302 return ; } 5304 Class cls = loadClass(tname); 5305 expression.setTypeClass(cls); 5306 expression.setDynamic(t.isDynamic()); 5307 return ; 5308 } 5309 5310 } else { 5318 int steps = 0; 5319 ClassNode currentClassNode = classNode; 5320 FieldNode field = null; 5321 do { 5322 if( (field = currentClassNode.getField(variableName)) != null ) { 5323 if (methodNode == null || !methodNode.isStatic() || field.isStatic() ) { 5324 if (field.isHolder()) { 5325 expression.setResolveFailed(true); 5326 expression.setFailure("reference type to be supported later"); 5327 return ; 5328 } else { 5329 String type = field.getType(); 5330 Class cls = loadClass(type); 5331 expression.setTypeClass(cls); 5332 expression.setDynamic(field.isDynamicType()); 5333 return ; 5334 } 5335 } 5336 } 5337 steps++; 5338 } while( (currentClassNode = currentClassNode.getOuterClass()) != null ); 5339 } 5340 5341 5344 String variableType = expression.getType(); 5345 if (variableType.length() > 0 && !variableType.equals("java.lang.Object")) { 5346 Class cls = loadClass(variableType); 5347 expression.setTypeClass(cls); 5348 return ; 5349 } 5350 } catch (Exception e) { 5351 log.warning(e.getMessage()); 5352 expression.setResolveFailed(true); 5353 expression.setFailure(e.getMessage()); 5354 } 5355 return ; 5356 } 5357 5358 public MetaMethod resolve(StaticMethodCallExpression staticCall) { 5359 if (staticCall.isResolveFailed()) { 5360 return null; 5361 } 5362 else if (staticCall.isTypeResolved()) { 5363 return staticCall.getMetaMethod(); 5364 } 5365 5366 String ownerTypeName = staticCall.getOwnerType(); 5367 String meth = staticCall.getMethod(); 5368 Class ownerClass = null; 5369 try { 5370 ownerClass = loadClass(ownerTypeName); 5371 } catch (Exception e) { 5372 staticCall.setResolveFailed(true); 5373 staticCall.setFailure("Owner type could not be resolved: " + e); 5374 return null; 5375 } 5376 5377 boolean isStaticCall = true; 5378 boolean isSuperCall = false; 5379 5380 List arglist = new ArrayList(); 5381 Expression args = staticCall.getArguments(); 5382 if (args instanceof TupleExpression) { 5383 TupleExpression tupleExpression = (TupleExpression) args; 5384 List argexps = tupleExpression.getExpressions(); 5385 for (int i = 0; i < argexps.size(); i++) { 5386 Expression expression = (Expression) argexps.get(i); 5387 Class cls = expression.getTypeClass(); 5388 if (cls == null) { 5389 staticCall.setResolveFailed(true); 5390 staticCall.setFailure("Argument type could not be resolved."); 5391 return null; 5392 } 5393 else { 5394 arglist.add(cls); 5395 } 5396 } 5397 } else if (args instanceof ClosureExpression) { 5398 staticCall.setResolveFailed(true); 5399 staticCall.setFailure("Resolving on Closure call not implemented yet. "); 5400 return null; } else { 5402 staticCall.setResolveFailed(true); 5403 staticCall.setFailure("Unknown argument expression type."); 5404 return null; 5405 } 5406 5407 5408 Class [] argsArray = new Class [arglist.size()]; 5409 arglist.toArray(argsArray); 5410 5411 if (ownerClass == Object .class) { 5412 staticCall.setResolveFailed(true); 5413 staticCall.setFailure("Resolving on java.lang.Object static call not supported. "); 5414 return null; } 5416 else if (ownerClass == null) { 5417 staticCall.setResolveFailed(true); 5418 staticCall.setFailure("Resolving on GrovyObject static call not implemented yet. "); 5419 return null; } 5421 else if (!isSuperCall && GroovyObject.class.isAssignableFrom(ownerClass) ) { staticCall.setResolveFailed(true); 5423 staticCall.setFailure("Resolving on GrovyObject static call not implemented yet. "); 5424 return null; 5425 } 5426 else if (ownerClass.isPrimitive()) { 5427 staticCall.setResolveFailed(true); 5428 staticCall.setFailure("Could not use primitive as method owner"); 5429 return null; } 5431 5432 5433 MetaMethod mmethod = MetaClassRegistry.getIntance(MetaClassRegistry.DONT_LOAD_DEFAULT).getDefinedMethod(ownerClass, meth, argsArray, isStaticCall); 5436 if (mmethod!= null) { 5437 staticCall.setMetaMethod(mmethod); 5438 } 5439 else { 5440 staticCall.setResolveFailed(true); 5441 staticCall.setFailure("Could not find MetaMethod in the MetaClass."); 5442 } 5443 return mmethod; 5444 } 5445 5446 private static Object asType(Object object, Class type) { 5449 if (object == null) { 5450 return null; 5451 } 5452 if (type.isInstance(object)) { 5453 return object; 5454 } 5455 if (type.equals(String .class)) { 5456 return object.toString(); 5457 } 5458 if (type.equals(Character .class)) { 5459 if (object instanceof Number ) { 5460 return asCharacter((Number ) object); 5461 } 5462 else { 5463 String text = object.toString(); 5464 if (text.length() == 1) { 5465 return new Character (text.charAt(0)); 5466 } 5467 else { 5468 throw new ClassCastException ("Cannot cast: " + text + " to a Character"); 5469 } 5470 } 5471 } 5472 if (Number .class.isAssignableFrom(type)) { 5473 if (object instanceof Character ) { 5474 return new Integer (((Character ) object).charValue()); 5475 } 5476 else if (object instanceof String ) { 5477 String c = (String ) object; 5478 if (c.length() == 1) { 5479 return new Integer (c.charAt(0)); 5480 } 5481 else { 5482 throw new ClassCastException ("Cannot cast: '" + c + "' to an Integer"); 5483 } 5484 } 5485 } 5486 if (object instanceof Number ) { 5487 Number n = (Number ) object; 5488 if (type.isPrimitive()) { 5489 if (type == byte.class) { 5490 return new Byte (n.byteValue()); 5491 } 5492 if (type == char.class) { 5493 return new Character ((char) n.intValue()); 5494 } 5495 if (type == short.class) { 5496 return new Short (n.shortValue()); 5497 } 5498 if (type == int.class) { 5499 return new Integer (n.intValue()); 5500 } 5501 if (type == long.class) { 5502 return new Long (n.longValue()); 5503 } 5504 if (type == float.class) { 5505 return new Float (n.floatValue()); 5506 } 5507 if (type == double.class) { 5508 Double answer = new Double (n.doubleValue()); 5509 if (!(n instanceof Double ) && (answer.doubleValue() == Double.NEGATIVE_INFINITY 5511 || answer.doubleValue() == Double.POSITIVE_INFINITY)) { 5512 throw new GroovyRuntimeException("Automatic coercion of "+n.getClass().getName() 5513 +" value "+n+" to double failed. Value is out of range."); 5514 } 5515 return answer; 5516 } 5517 } 5518 else { 5519 if (Number .class.isAssignableFrom(type)) { 5520 if (type == Byte .class) { 5521 return new Byte (n.byteValue()); 5522 } 5523 if (type == Character .class) { 5524 return new Character ((char) n.intValue()); 5525 } 5526 if (type == Short .class) { 5527 return new Short (n.shortValue()); 5528 } 5529 if (type == Integer .class) { 5530 return new Integer (n.intValue()); 5531 } 5532 if (type == Long .class) { 5533 return new Long (n.longValue()); 5534 } 5535 if (type == Float .class) { 5536 return new Float (n.floatValue()); 5537 } 5538 if (type == Double .class) { 5539 Double answer = new Double (n.doubleValue()); 5540 if (!(n instanceof Double ) && (answer.doubleValue() == Double.NEGATIVE_INFINITY 5542 || answer.doubleValue() == Double.POSITIVE_INFINITY)) { 5543 throw new GroovyRuntimeException("Automatic coercion of "+n.getClass().getName() 5544 +" value "+n+" to double failed. Value is out of range."); 5545 } 5546 return answer; 5547 } 5548 5549 } 5550 } 5551 } 5552 if (type == Boolean .class) { 5553 return asBool(object) ? Boolean.TRUE : Boolean.FALSE; 5554 } 5555 return object; 5556 } 5557 5558 private static boolean asBool(Object object) { 5559 if (object instanceof Boolean ) { 5560 Boolean booleanValue = (Boolean ) object; 5561 return booleanValue.booleanValue(); 5562 } 5563 else if (object instanceof Matcher ) { 5564 Matcher matcher = (Matcher ) object; 5565 RegexSupport.setLastMatcher(matcher); 5566 return matcher.find(); 5567 } 5568 else if (object instanceof Collection) { 5569 Collection collection = (Collection) object; 5570 return !collection.isEmpty(); 5571 } 5572 else if (object instanceof Number ) { 5573 Number n = (Number ) object; 5574 return n.intValue() != 0; 5575 } 5576 else { 5577 return object != null; 5578 } 5579 } 5580 private static Character asCharacter(Number value) { 5581 return new Character ((char) value.intValue()); 5582 } 5583 5584 private static Character asCharacter(String text) { 5585 return new Character (text.charAt(0)); 5586 } 5587} 5588 | Popular Tags |