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