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