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