001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package com.db4o.nativequery.optimization;
022:
023: import EDU.purdue.cs.bloat.editor.ClassEditor;
024: import EDU.purdue.cs.bloat.editor.Label;
025: import EDU.purdue.cs.bloat.editor.LocalVariable;
026: import EDU.purdue.cs.bloat.editor.MemberRef;
027: import EDU.purdue.cs.bloat.editor.MethodEditor;
028: import EDU.purdue.cs.bloat.editor.NameAndType;
029: import EDU.purdue.cs.bloat.editor.Opcode;
030: import EDU.purdue.cs.bloat.editor.Type;
031: import EDU.purdue.cs.bloat.file.ClassSource;
032: import EDU.purdue.cs.bloat.reflect.Modifiers;
033:
034: import com.db4o.foundation.Collection4;
035: import com.db4o.foundation.Iterator4;
036: import com.db4o.instrumentation.core.*;
037: import com.db4o.instrumentation.util.*;
038: import com.db4o.internal.query.Db4oEnhancedFilter;
039: import com.db4o.nativequery.expr.AndExpression;
040: import com.db4o.nativequery.expr.BoolConstExpression;
041: import com.db4o.nativequery.expr.ComparisonExpression;
042: import com.db4o.nativequery.expr.Expression;
043: import com.db4o.nativequery.expr.ExpressionVisitor;
044: import com.db4o.nativequery.expr.NotExpression;
045: import com.db4o.nativequery.expr.OrExpression;
046: import com.db4o.nativequery.expr.cmp.ComparisonOperator;
047: import com.db4o.nativequery.expr.cmp.operand.*;
048: import com.db4o.query.Constraint;
049: import com.db4o.query.Query;
050:
051: public class SODABloatMethodBuilder {
052: private final static boolean LOG_BYTECODE = false;
053:
054: private MethodEditor methodEditor;
055:
056: private MemberRef descendRef;
057: private MemberRef constrainRef;
058: private MemberRef greaterRef;
059: private MemberRef smallerRef;
060: private MemberRef containsRef;
061: private MemberRef startsWithRef;
062: private MemberRef endsWithRef;
063: private MemberRef notRef;
064: private MemberRef andRef;
065: private MemberRef orRef;
066: private MemberRef identityRef;
067: private Type queryType;
068:
069: private class SODABloatMethodVisitor implements ExpressionVisitor {
070:
071: private Class predicateClass;
072: private Class candidateClass;
073: private ClassSource classSource;
074:
075: public SODABloatMethodVisitor(Class predicateClass,
076: ClassLoader classLoader, ClassSource classSource) {
077: this .predicateClass = predicateClass;
078: this .classSource = classSource;
079: }
080:
081: public void visit(AndExpression expression) {
082: expression.left().accept(this );
083: expression.right().accept(this );
084: methodEditor.addInstruction(Opcode.opc_invokeinterface,
085: andRef);
086: }
087:
088: public void visit(BoolConstExpression expression) {
089: methodEditor.addInstruction(Opcode.opc_aload,
090: new LocalVariable("query", queryType, 1));
091: //throw new RuntimeException("No boolean constants expected in parsed expression tree");
092: }
093:
094: public void visit(OrExpression expression) {
095: expression.left().accept(this );
096: expression.right().accept(this );
097: methodEditor.addInstruction(Opcode.opc_invokeinterface,
098: orRef);
099: }
100:
101: public void visit(final ComparisonExpression expression) {
102: methodEditor.addInstruction(Opcode.opc_aload,
103: new LocalVariable("query", queryType, 1));
104: Iterator4 fieldNames = fieldNames(expression.left());
105: while (fieldNames.moveNext()) {
106: methodEditor.addInstruction(Opcode.opc_ldc, fieldNames
107: .current());
108: methodEditor.addInstruction(Opcode.opc_invokeinterface,
109: descendRef);
110: }
111: expression.right().accept(
112: new ComparisonBytecodeGeneratingVisitor(
113: methodEditor, predicateClass,
114: candidateClass, classSource));
115: methodEditor.addInstruction(Opcode.opc_invokeinterface,
116: constrainRef);
117: ComparisonOperator op = expression.op();
118: if (op.equals(ComparisonOperator.EQUALS)) {
119: return;
120: }
121: if (op.equals(ComparisonOperator.IDENTITY)) {
122: methodEditor.addInstruction(Opcode.opc_invokeinterface,
123: identityRef);
124: return;
125: }
126: if (op.equals(ComparisonOperator.GREATER)) {
127: methodEditor.addInstruction(Opcode.opc_invokeinterface,
128: greaterRef);
129: return;
130: }
131: if (op.equals(ComparisonOperator.SMALLER)) {
132: methodEditor.addInstruction(Opcode.opc_invokeinterface,
133: smallerRef);
134: return;
135: }
136: if (op.equals(ComparisonOperator.CONTAINS)) {
137: methodEditor.addInstruction(Opcode.opc_invokeinterface,
138: containsRef);
139: return;
140: }
141: if (op.equals(ComparisonOperator.STARTSWITH)) {
142: methodEditor.addInstruction(Opcode.opc_ldc,
143: new Integer(1));
144: methodEditor.addInstruction(Opcode.opc_invokeinterface,
145: startsWithRef);
146: return;
147: }
148: if (op.equals(ComparisonOperator.ENDSWITH)) {
149: methodEditor.addInstruction(Opcode.opc_ldc,
150: new Integer(1));
151: methodEditor.addInstruction(Opcode.opc_invokeinterface,
152: endsWithRef);
153: return;
154: }
155: throw new RuntimeException("Cannot interpret constraint: "
156: + op);
157: }
158:
159: public void visit(NotExpression expression) {
160: expression.expr().accept(this );
161: methodEditor.addInstruction(Opcode.opc_invokeinterface,
162: notRef);
163: }
164:
165: private Iterator4 fieldNames(FieldValue fieldValue) {
166: Collection4 coll = new Collection4();
167: ComparisonOperand curOp = fieldValue;
168: while (curOp instanceof FieldValue) {
169: FieldValue curField = (FieldValue) curOp;
170: coll.prepend(curField.fieldName());
171: curOp = curField.parent();
172: }
173: return coll.iterator();
174: }
175: }
176:
177: public SODABloatMethodBuilder() {
178: buildMethodReferences();
179: }
180:
181: public MethodEditor injectOptimization(Expression expr,
182: ClassEditor classEditor, ClassLoader classLoader,
183: ClassSource classSource) {
184: classEditor.addInterface(Db4oEnhancedFilter.class);
185: methodEditor = new MethodEditor(classEditor, Modifiers.PUBLIC,
186: Void.TYPE,
187: NativeQueryEnhancer.OPTIMIZE_QUERY_METHOD_NAME,
188: new Class[] { Query.class }, new Class[] {});
189: LabelGenerator labelGen = new LabelGenerator();
190: methodEditor.addLabel(labelGen.createLabel(true));
191: try {
192: Class predicateClass = classLoader.loadClass(BloatUtil
193: .normalizeClassName(classEditor.name()));
194: expr.accept(new SODABloatMethodVisitor(predicateClass,
195: classLoader, classSource));
196: methodEditor.addInstruction(Opcode.opc_pop);
197: methodEditor.addLabel(labelGen.createLabel(false));
198: methodEditor.addInstruction(Opcode.opc_return);
199: methodEditor.addLabel(labelGen.createLabel(true));
200: if (LOG_BYTECODE) {
201: methodEditor.print(System.out);
202: }
203: return methodEditor;
204: } catch (ClassNotFoundException exc) {
205: throw new RuntimeException(exc.getMessage());
206: }
207: }
208:
209: private void buildMethodReferences() {
210: queryType = createType(Query.class);
211: descendRef = createMethodReference(Query.class, "descend",
212: new Class[] { String.class }, Query.class);
213: constrainRef = createMethodReference(Query.class, "constrain",
214: new Class[] { Object.class }, Constraint.class);
215: greaterRef = createMethodReference(Constraint.class, "greater",
216: new Class[] {}, Constraint.class);
217: smallerRef = createMethodReference(Constraint.class, "smaller",
218: new Class[] {}, Constraint.class);
219: containsRef = createMethodReference(Constraint.class,
220: "contains", new Class[] {}, Constraint.class);
221: startsWithRef = createMethodReference(Constraint.class,
222: "startsWith", new Class[] { Boolean.TYPE },
223: Constraint.class);
224: endsWithRef = createMethodReference(Constraint.class,
225: "endsWith", new Class[] { Boolean.TYPE },
226: Constraint.class);
227: notRef = createMethodReference(Constraint.class, "not",
228: new Class[] {}, Constraint.class);
229: andRef = createMethodReference(Constraint.class, "and",
230: new Class[] { Constraint.class }, Constraint.class);
231: orRef = createMethodReference(Constraint.class, "or",
232: new Class[] { Constraint.class }, Constraint.class);
233: identityRef = createMethodReference(Constraint.class,
234: "identity", new Class[] {}, Constraint.class);
235: }
236:
237: private MemberRef createMethodReference(Class parent, String name,
238: Class[] args, Class ret) {
239: Type[] argTypes = new Type[args.length];
240: for (int argIdx = 0; argIdx < args.length; argIdx++) {
241: argTypes[argIdx] = createType(args[argIdx]);
242: }
243: NameAndType nameAndType = new NameAndType(name, Type.getType(
244: argTypes, createType(ret)));
245: return new MemberRef(createType(parent), nameAndType);
246: }
247:
248: private Type createType(Class clazz) {
249: return Type.getType(clazz);
250: }
251: }
|