001: /*
002: * Copyright 2001-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: /*
017: * $Id: MethodGenerator.java,v 1.16 2005/02/17 19:08:03 ytalwar Exp $
018: */
019:
020: package org.apache.xalan.xsltc.compiler.util;
021:
022: import java.util.Hashtable;
023:
024: import org.apache.bcel.generic.ALOAD;
025: import org.apache.bcel.generic.ASTORE;
026: import org.apache.bcel.generic.ConstantPoolGen;
027: import org.apache.bcel.generic.ICONST;
028: import org.apache.bcel.generic.ILOAD;
029: import org.apache.bcel.generic.INVOKEINTERFACE;
030: import org.apache.bcel.generic.ISTORE;
031: import org.apache.bcel.generic.Instruction;
032: import org.apache.bcel.generic.InstructionHandle;
033: import org.apache.bcel.generic.InstructionList;
034: import org.apache.bcel.generic.LocalVariableGen;
035: import org.apache.bcel.generic.MethodGen;
036: import org.apache.bcel.generic.Type;
037: import org.apache.xalan.xsltc.compiler.Pattern;
038:
039: /**
040: * @author Jacek Ambroziak
041: * @author Santiago Pericas-Geertsen
042: */
043: public class MethodGenerator extends MethodGen implements
044: org.apache.xalan.xsltc.compiler.Constants {
045: protected static final int INVALID_INDEX = -1;
046:
047: private static final String START_ELEMENT_SIG = "(" + STRING_SIG
048: + ")V";
049: private static final String END_ELEMENT_SIG = START_ELEMENT_SIG;
050:
051: private InstructionList _mapTypeSub;
052:
053: private static final int DOM_INDEX = 1;
054: private static final int ITERATOR_INDEX = 2;
055: private static final int HANDLER_INDEX = 3;
056:
057: private Instruction _iloadCurrent;
058: private Instruction _istoreCurrent;
059: private final Instruction _astoreHandler;
060: private final Instruction _aloadHandler;
061: private final Instruction _astoreIterator;
062: private final Instruction _aloadIterator;
063: private final Instruction _aloadDom;
064: private final Instruction _astoreDom;
065:
066: private final Instruction _startElement;
067: private final Instruction _endElement;
068: private final Instruction _startDocument;
069: private final Instruction _endDocument;
070: private final Instruction _attribute;
071: private final Instruction _uniqueAttribute;
072: private final Instruction _namespace;
073:
074: private final Instruction _setStartNode;
075: private final Instruction _reset;
076: private final Instruction _nextNode;
077:
078: private SlotAllocator _slotAllocator;
079: private boolean _allocatorInit = false;
080: /**
081: * A mapping between patterns and instruction lists used by
082: * test sequences to avoid compiling the same pattern multiple
083: * times. Note that patterns whose kernels are "*", "node()"
084: * and "@*" can between shared by test sequences.
085: */
086: private Hashtable _preCompiled = new Hashtable();
087:
088: public MethodGenerator(int access_flags, Type return_type,
089: Type[] arg_types, String[] arg_names, String method_name,
090: String class_name, InstructionList il, ConstantPoolGen cpg) {
091: super (access_flags, return_type, arg_types, arg_names,
092: method_name, class_name, il, cpg);
093:
094: _astoreHandler = new ASTORE(HANDLER_INDEX);
095: _aloadHandler = new ALOAD(HANDLER_INDEX);
096: _astoreIterator = new ASTORE(ITERATOR_INDEX);
097: _aloadIterator = new ALOAD(ITERATOR_INDEX);
098: _aloadDom = new ALOAD(DOM_INDEX);
099: _astoreDom = new ASTORE(DOM_INDEX);
100:
101: final int startElement = cpg.addInterfaceMethodref(
102: TRANSLET_OUTPUT_INTERFACE, "startElement",
103: START_ELEMENT_SIG);
104: _startElement = new INVOKEINTERFACE(startElement, 2);
105:
106: final int endElement = cpg.addInterfaceMethodref(
107: TRANSLET_OUTPUT_INTERFACE, "endElement",
108: END_ELEMENT_SIG);
109: _endElement = new INVOKEINTERFACE(endElement, 2);
110:
111: final int attribute = cpg.addInterfaceMethodref(
112: TRANSLET_OUTPUT_INTERFACE, "addAttribute", "("
113: + STRING_SIG + STRING_SIG + ")V");
114: _attribute = new INVOKEINTERFACE(attribute, 3);
115:
116: final int uniqueAttribute = cpg.addInterfaceMethodref(
117: TRANSLET_OUTPUT_INTERFACE, "addUniqueAttribute", "("
118: + STRING_SIG + STRING_SIG + "I)V");
119: _uniqueAttribute = new INVOKEINTERFACE(uniqueAttribute, 4);
120:
121: final int namespace = cpg.addInterfaceMethodref(
122: TRANSLET_OUTPUT_INTERFACE,
123: "namespaceAfterStartElement", "(" + STRING_SIG
124: + STRING_SIG + ")V");
125: _namespace = new INVOKEINTERFACE(namespace, 3);
126:
127: int index = cpg.addInterfaceMethodref(
128: TRANSLET_OUTPUT_INTERFACE, "startDocument", "()V");
129: _startDocument = new INVOKEINTERFACE(index, 1);
130:
131: index = cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE,
132: "endDocument", "()V");
133: _endDocument = new INVOKEINTERFACE(index, 1);
134:
135: index = cpg.addInterfaceMethodref(NODE_ITERATOR,
136: SET_START_NODE, SET_START_NODE_SIG);
137: _setStartNode = new INVOKEINTERFACE(index, 2);
138:
139: index = cpg.addInterfaceMethodref(NODE_ITERATOR, "reset", "()"
140: + NODE_ITERATOR_SIG);
141: _reset = new INVOKEINTERFACE(index, 1);
142:
143: index = cpg
144: .addInterfaceMethodref(NODE_ITERATOR, NEXT, NEXT_SIG);
145: _nextNode = new INVOKEINTERFACE(index, 1);
146:
147: _slotAllocator = new SlotAllocator();
148: _slotAllocator.initialize(getLocalVariables());
149: _allocatorInit = true;
150: }
151:
152: /**
153: * Allocates a local variable. If the slot allocator has already been
154: * initialized, then call addLocalVariable2() so that the new variable
155: * is known to the allocator. Failing to do this may cause the allocator
156: * to return a slot that is already in use.
157: */
158: public LocalVariableGen addLocalVariable(String name, Type type,
159: InstructionHandle start, InstructionHandle end) {
160: return (_allocatorInit) ? addLocalVariable2(name, type, start)
161: : super .addLocalVariable(name, type, start, end);
162: }
163:
164: public LocalVariableGen addLocalVariable2(String name, Type type,
165: InstructionHandle start) {
166: return super .addLocalVariable(name, type, _slotAllocator
167: .allocateSlot(type), start, null);
168: }
169:
170: public void removeLocalVariable(LocalVariableGen lvg) {
171: _slotAllocator.releaseSlot(lvg);
172: super .removeLocalVariable(lvg);
173: }
174:
175: public Instruction loadDOM() {
176: return _aloadDom;
177: }
178:
179: public Instruction storeDOM() {
180: return _astoreDom;
181: }
182:
183: public Instruction storeHandler() {
184: return _astoreHandler;
185: }
186:
187: public Instruction loadHandler() {
188: return _aloadHandler;
189: }
190:
191: public Instruction storeIterator() {
192: return _astoreIterator;
193: }
194:
195: public Instruction loadIterator() {
196: return _aloadIterator;
197: }
198:
199: public final Instruction setStartNode() {
200: return _setStartNode;
201: }
202:
203: public final Instruction reset() {
204: return _reset;
205: }
206:
207: public final Instruction nextNode() {
208: return _nextNode;
209: }
210:
211: public final Instruction startElement() {
212: return _startElement;
213: }
214:
215: public final Instruction endElement() {
216: return _endElement;
217: }
218:
219: public final Instruction startDocument() {
220: return _startDocument;
221: }
222:
223: public final Instruction endDocument() {
224: return _endDocument;
225: }
226:
227: public final Instruction attribute() {
228: return _attribute;
229: }
230:
231: public final Instruction uniqueAttribute() {
232: return _uniqueAttribute;
233: }
234:
235: public final Instruction namespace() {
236: return _namespace;
237: }
238:
239: public Instruction loadCurrentNode() {
240: if (_iloadCurrent == null) {
241: int idx = getLocalIndex("current");
242: if (idx > 0)
243: _iloadCurrent = new ILOAD(idx);
244: else
245: _iloadCurrent = new ICONST(0);
246: }
247: return _iloadCurrent;
248: }
249:
250: public Instruction storeCurrentNode() {
251: return _istoreCurrent != null ? _istoreCurrent
252: : (_istoreCurrent = new ISTORE(getLocalIndex("current")));
253: }
254:
255: /** by default context node is the same as current node. MK437 */
256: public Instruction loadContextNode() {
257: return loadCurrentNode();
258: }
259:
260: public Instruction storeContextNode() {
261: return storeCurrentNode();
262: }
263:
264: public int getLocalIndex(String name) {
265: return getLocalVariable(name).getIndex();
266: }
267:
268: public LocalVariableGen getLocalVariable(String name) {
269: final LocalVariableGen[] vars = getLocalVariables();
270: for (int i = 0; i < vars.length; i++)
271: if (vars[i].getName().equals(name))
272: return vars[i];
273: return null;
274: }
275:
276: public void setMaxLocals() {
277:
278: // Get the current number of local variable slots
279: int maxLocals = super .getMaxLocals();
280: int prevLocals = maxLocals;
281:
282: // Get numer of actual variables
283: final LocalVariableGen[] localVars = super .getLocalVariables();
284: if (localVars != null) {
285: if (localVars.length > maxLocals)
286: maxLocals = localVars.length;
287: }
288:
289: // We want at least 5 local variable slots (for parameters)
290: if (maxLocals < 5)
291: maxLocals = 5;
292:
293: super .setMaxLocals(maxLocals);
294: }
295:
296: /**
297: * Add a pre-compiled pattern to this mode.
298: */
299: public void addInstructionList(Pattern pattern,
300: InstructionList ilist) {
301: _preCompiled.put(pattern, ilist);
302: }
303:
304: /**
305: * Get the instruction list for a pre-compiled pattern. Used by
306: * test sequences to avoid compiling patterns more than once.
307: */
308: public InstructionList getInstructionList(Pattern pattern) {
309: return (InstructionList) _preCompiled.get(pattern);
310: }
311:
312: }
|