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