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