KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > db4o > nativequery > optimization > ComparisonBytecodeGeneratingVisitor


1 /* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com
2
3 This file is part of the db4o open source object database.
4
5 db4o is free software; you can redistribute it and/or modify it under
6 the terms of version 2 of the GNU General Public License as published
7 by the Free Software Foundation and as clarified by db4objects' GPL
8 interpretation policy, available at
9 http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
10 Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
11 Suite 350, San Mateo, CA 94403, USA.
12
13 db4o is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */

21 package com.db4o.nativequery.optimization;
22
23 import java.lang.reflect.*;
24 import java.util.*;
25
26 import EDU.purdue.cs.bloat.editor.*;
27 import EDU.purdue.cs.bloat.editor.Type;
28
29 import com.db4o.nativequery.expr.cmp.*;
30 import com.db4o.nativequery.expr.cmp.field.*;
31
32 class ComparisonBytecodeGeneratingVisitor implements ComparisonOperandVisitor {
33     private MethodEditor methodEditor;
34     private Class JavaDoc predicateClass;
35     private Class JavaDoc candidateClass;
36     
37     private Map conversions;
38     private boolean inArithmetic=false;
39     private Class JavaDoc opClass=null;
40     private Class JavaDoc staticRoot=null;
41
42     public ComparisonBytecodeGeneratingVisitor(MethodEditor methodEditor,Class JavaDoc predicateClass,Class JavaDoc candidateClass) {
43         this.methodEditor = methodEditor;
44         this.predicateClass=predicateClass;
45         this.candidateClass=candidateClass;
46         buildConversions();
47     }
48
49     public void visit(ConstValue operand) {
50         Object JavaDoc value = operand.value();
51         if(value!=null) {
52             opClass=value.getClass();
53             prepareConversion(value.getClass(),!inArithmetic);
54         }
55         methodEditor.addInstruction(Opcode.opc_ldc,value);
56         if(value!=null) {
57             applyConversion(value.getClass(),!inArithmetic);
58         }
59         // FIXME handle char, boolean,...
60
}
61
62     public void visit(FieldValue fieldValue) {
63         try {
64             Class JavaDoc lastFieldClass = deduceFieldClass(fieldValue);
65             Class JavaDoc parentClass=deduceFieldClass(fieldValue.parent());
66             boolean needConversion=lastFieldClass.isPrimitive();
67             prepareConversion(lastFieldClass,!inArithmetic&&needConversion);
68             
69             fieldValue.parent().accept(this);
70             if(staticRoot!=null) {
71                 methodEditor.addInstruction(Opcode.opc_getstatic,createFieldReference(staticRoot, lastFieldClass,fieldValue.fieldName()));
72                 staticRoot=null;
73                 return;
74             }
75             MemberRef fieldRef=createFieldReference(parentClass,lastFieldClass,fieldValue.fieldName());
76             methodEditor.addInstruction(Opcode.opc_getfield,fieldRef);
77             
78             applyConversion(lastFieldClass,!inArithmetic&&needConversion);
79         } catch (Exception JavaDoc exc) {
80             throw new RuntimeException JavaDoc(exc.getMessage());
81         }
82     }
83
84     public void visit(CandidateFieldRoot root) {
85         methodEditor.addInstruction(Opcode.opc_aload,new LocalVariable(1));
86     }
87
88     public void visit(PredicateFieldRoot root) {
89         methodEditor.addInstruction(Opcode.opc_aload,new LocalVariable(0));
90     }
91
92     public void visit(StaticFieldRoot root) {
93         try {
94             staticRoot=Class.forName(root.className());
95         } catch (ClassNotFoundException JavaDoc e) {
96             e.printStackTrace();
97         }
98     }
99
100     public void visit(ArrayAccessValue operand) {
101         Class JavaDoc cmpType=deduceFieldClass(operand.parent()).getComponentType();
102         prepareConversion(cmpType, !inArithmetic);
103         operand.parent().accept(this);
104         boolean outerInArithmetic=inArithmetic;
105         inArithmetic=true;
106         operand.index().accept(this);
107         inArithmetic=outerInArithmetic;
108         int opcode=Opcode.opc_aaload;
109         if(cmpType==Integer.TYPE) {
110             opcode=Opcode.opc_iaload;
111         }
112         if(cmpType==Long.TYPE) {
113             opcode=Opcode.opc_laload;
114         }
115         if(cmpType==Float.TYPE) {
116             opcode=Opcode.opc_faload;
117         }
118         if(cmpType==Double.TYPE) {
119             opcode=Opcode.opc_daload;
120         }
121         methodEditor.addInstruction(opcode);
122         applyConversion(cmpType, !inArithmetic);
123     }
124
125     public void visit(MethodCallValue operand) {
126         Class JavaDoc rcvType=deduceFieldClass(operand.parent());
127         Method method=ReflectUtil.methodFor(rcvType, operand.methodName(), operand.paramTypes());
128         Class JavaDoc retType=method.getReturnType();
129         // FIXME: this should be handled within conversions
130
boolean needConversion=retType.isPrimitive();
131         prepareConversion(retType, !inArithmetic&&needConversion);
132         operand.parent().accept(this);
133         boolean oldInArithmetic=inArithmetic;
134         for (int paramIdx = 0; paramIdx < operand.args().length; paramIdx++) {
135             inArithmetic=operand.paramTypes()[paramIdx].isPrimitive();
136             operand.args()[paramIdx].accept(this);
137         }
138         inArithmetic=oldInArithmetic;
139         // FIXME: invokeinterface
140
int opcode=((method.getModifiers()&Modifier.STATIC)!=0 ? Opcode.opc_invokestatic : Opcode.opc_invokevirtual);
141         methodEditor.addInstruction(opcode,createMethodReference(method.getDeclaringClass(), method.getName(), method.getParameterTypes(), method.getReturnType()));
142         applyConversion(retType, !inArithmetic&&needConversion);
143     }
144
145     public void visit(ArithmeticExpression operand) {
146         boolean oldInArithmetic=inArithmetic;
147         inArithmetic=true;
148         Instruction newInstr=prepareConversion(opClass,!oldInArithmetic,true);
149         operand.left().accept(this);
150         operand.right().accept(this);
151         Class JavaDoc operandType=arithmeticType(operand);
152         int opcode=Integer.MIN_VALUE;
153         switch(operand.op().id()) {
154             case ArithmeticOperator.ADD_ID:
155                 if(operandType==Double JavaDoc.class) {
156                     opcode=Opcode.opc_dadd;
157                     break;
158                 }
159                 if(operandType==Float JavaDoc.class) {
160                     opcode=Opcode.opc_fadd;
161                     break;
162                 }
163                 if(operandType==Long JavaDoc.class) {
164                     opcode=Opcode.opc_ladd;
165                     break;
166                 }
167                 opcode=Opcode.opc_iadd;
168                 break;
169             case ArithmeticOperator.SUBTRACT_ID:
170                 if(operandType==Double JavaDoc.class) {
171                     opcode=Opcode.opc_dsub;
172                     break;
173                 }
174                 if(operandType==Float JavaDoc.class) {
175                     opcode=Opcode.opc_fsub;
176                     break;
177                 }
178                 if(operandType==Long JavaDoc.class) {
179                     opcode=Opcode.opc_lsub;
180                     break;
181                 }
182                 opcode=Opcode.opc_isub;
183                 break;
184             case ArithmeticOperator.MULTIPLY_ID:
185                 if(operandType==Double JavaDoc.class) {
186                     opcode=Opcode.opc_dmul;
187                     break;
188                 }
189                 if(operandType==Float JavaDoc.class) {
190                     opcode=Opcode.opc_fmul;
191                     break;
192                 }
193                 if(operandType==Long JavaDoc.class) {
194                     opcode=Opcode.opc_lmul;
195                     break;
196                 }
197                 opcode=Opcode.opc_imul;
198                 break;
199             case ArithmeticOperator.DIVIDE_ID:
200                 if(operandType==Double JavaDoc.class) {
201                     opcode=Opcode.opc_ddiv;
202                     break;
203                 }
204                 if(operandType==Float JavaDoc.class) {
205                     opcode=Opcode.opc_fdiv;
206                     break;
207                 }
208                 if(operandType==Long JavaDoc.class) {
209                     opcode=Opcode.opc_ldiv;
210                     break;
211                 }
212                 opcode=Opcode.opc_idiv;
213                 break;
214             default:
215                 throw new RuntimeException JavaDoc("Unknown operand: "+operand.op());
216         }
217         methodEditor.addInstruction(opcode);
218         if(newInstr!=null) {
219             newInstr.setOperand(createType(opClass));
220         }
221         applyConversion(opClass,!oldInArithmetic);
222         inArithmetic=oldInArithmetic;
223         // FIXME: need to map dX,fX,...
224
}
225
226     private Class JavaDoc deduceFieldClass(ComparisonOperand fieldValue) {
227         TypeDeducingVisitor visitor=new TypeDeducingVisitor(predicateClass,candidateClass);
228         fieldValue.accept(visitor);
229         return visitor.operandClass();
230     }
231
232     private MemberRef createFieldReference(Class JavaDoc parentClass,Class JavaDoc fieldClass,String JavaDoc name) throws NoSuchFieldException JavaDoc {
233         NameAndType nameAndType=new NameAndType(name,createType(fieldClass));
234         return new MemberRef(createType(parentClass),nameAndType);
235     }
236
237
238     private Class JavaDoc arithmeticType(ComparisonOperand operand) {
239         if (operand instanceof ConstValue) {
240             return ((ConstValue) operand).value().getClass();
241         }
242         if (operand instanceof FieldValue) {
243             try {
244                 return deduceFieldClass((FieldValue) operand);
245             } catch (Exception JavaDoc e) {
246                 e.printStackTrace();
247                 return null;
248             }
249         }
250         if (operand instanceof ArithmeticExpression) {
251             ArithmeticExpression expr=(ArithmeticExpression)operand;
252             Class JavaDoc left=arithmeticType(expr.left());
253             Class JavaDoc right=arithmeticType(expr.right());
254             if(left==Double JavaDoc.class||right==Double JavaDoc.class) {
255                 return Double JavaDoc.class;
256             }
257             if(left==Float JavaDoc.class||right==Float JavaDoc.class) {
258                 return Float JavaDoc.class;
259             }
260             if(left==Long JavaDoc.class||right==Long JavaDoc.class) {
261                 return Long JavaDoc.class;
262             }
263             return Integer JavaDoc.class;
264         }
265         return null;
266     }
267
268     private Instruction prepareConversion(Class JavaDoc clazz,boolean canApply) {
269         return prepareConversion(clazz,canApply,false);
270     }
271
272     private Instruction prepareConversion(Class JavaDoc clazz,boolean canApply,boolean force) {
273         if((force||conversions.containsKey(clazz))&&canApply) {
274             Class JavaDoc[] convSpec=(Class JavaDoc[])conversions.get(clazz);
275             Instruction newInstruction=new Instruction(Opcode.opc_new,(convSpec==null ? null : createType(convSpec[0])));
276             methodEditor.addInstruction(newInstruction);
277             methodEditor.addInstruction(Opcode.opc_dup);
278             return newInstruction;
279         }
280         return null;
281     }
282
283     private void applyConversion(Class JavaDoc clazz,boolean canApply) {
284         if(conversions.containsKey(clazz)&&canApply) {
285             Class JavaDoc[] convSpec=(Class JavaDoc[])conversions.get(clazz);
286             methodEditor.addInstruction(Opcode.opc_invokespecial,createMethodReference(convSpec[0],"<init>",new Class JavaDoc[]{convSpec[1]},Void.TYPE));
287         }
288     }
289
290     private MemberRef createMethodReference(Class JavaDoc parent,String JavaDoc name,Class JavaDoc[] args,Class JavaDoc ret) {
291         Type[] argTypes=new Type[args.length];
292         for (int argIdx = 0; argIdx < args.length; argIdx++) {
293             argTypes[argIdx]=createType(args[argIdx]);
294         }
295         NameAndType nameAndType=new NameAndType(name,Type.getType(argTypes,createType(ret)));
296         return new MemberRef(createType(parent),nameAndType);
297     }
298     
299     private Type createType(Class JavaDoc clazz) {
300         return Type.getType(clazz);
301     }
302     
303     private void buildConversions() {
304         conversions=new HashMap();
305         conversions.put(Integer JavaDoc.class,new Class JavaDoc[]{Integer JavaDoc.class,Integer.TYPE});
306         conversions.put(Long JavaDoc.class,new Class JavaDoc[]{Long JavaDoc.class,Long.TYPE});
307         conversions.put(Short JavaDoc.class,new Class JavaDoc[]{Short JavaDoc.class,Short.TYPE});
308         conversions.put(Byte JavaDoc.class,new Class JavaDoc[]{Byte JavaDoc.class,Byte.TYPE});
309         conversions.put(Double JavaDoc.class,new Class JavaDoc[]{Double JavaDoc.class,Double.TYPE});
310         conversions.put(Float JavaDoc.class,new Class JavaDoc[]{Float JavaDoc.class,Float.TYPE});
311         // FIXME this must be handled somewhere else - FieldValue, etc.
312
conversions.put(Integer.TYPE,conversions.get(Integer JavaDoc.class));
313         conversions.put(Long.TYPE,conversions.get(Long JavaDoc.class));
314         conversions.put(Short.TYPE,conversions.get(Short JavaDoc.class));
315         conversions.put(Byte.TYPE,conversions.get(Byte JavaDoc.class));
316         conversions.put(Double.TYPE,conversions.get(Double JavaDoc.class));
317         conversions.put(Float.TYPE,conversions.get(Float JavaDoc.class));
318     }
319 }
320
Popular Tags