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