/* * Copyright 2001-2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Id: MethodGenerator.java,v 1.15 2004/02/16 22:26:44 minchau Exp $ */ package com.sun.org.apache.xalan.internal.xsltc.compiler.util; import com.sun.org.apache.bcel.internal.generic.ALOAD; import com.sun.org.apache.bcel.internal.generic.ASTORE; import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; import com.sun.org.apache.bcel.internal.generic.ICONST; import com.sun.org.apache.bcel.internal.generic.ILOAD; import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; import com.sun.org.apache.bcel.internal.generic.ISTORE; import com.sun.org.apache.bcel.internal.generic.Instruction; import com.sun.org.apache.bcel.internal.generic.InstructionHandle; import com.sun.org.apache.bcel.internal.generic.InstructionList; import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; import com.sun.org.apache.bcel.internal.generic.MethodGen; import com.sun.org.apache.bcel.internal.generic.Type; /** * @author Jacek Ambroziak * @author Santiago Pericas-Geertsen */ public class MethodGenerator extends MethodGen implements com.sun.org.apache.xalan.internal.xsltc.compiler.Constants { protected static final int INVALID_INDEX = -1; private static final String START_ELEMENT_SIG = "(" + STRING_SIG + ")V"; private static final String END_ELEMENT_SIG = START_ELEMENT_SIG; private InstructionList _mapTypeSub; private static final int DOM_INDEX = 1; private static final int ITERATOR_INDEX = 2; private static final int HANDLER_INDEX = 3; private Instruction _iloadCurrent; private Instruction _istoreCurrent; private final Instruction _astoreHandler; private final Instruction _aloadHandler; private final Instruction _astoreIterator; private final Instruction _aloadIterator; private final Instruction _aloadDom; private final Instruction _astoreDom; private final Instruction _startElement; private final Instruction _endElement; private final Instruction _startDocument; private final Instruction _endDocument; private final Instruction _attribute; private final Instruction _uniqueAttribute; private final Instruction _namespace; private final Instruction _setStartNode; private final Instruction _reset; private final Instruction _nextNode; private SlotAllocator _slotAllocator; private boolean _allocatorInit = false; public MethodGenerator(int access_flags, Type return_type, Type[] arg_types, String[] arg_names, String method_name, String class_name, InstructionList il, ConstantPoolGen cpg) { super(access_flags, return_type, arg_types, arg_names, method_name, class_name, il, cpg); _astoreHandler = new ASTORE(HANDLER_INDEX); _aloadHandler = new ALOAD(HANDLER_INDEX); _astoreIterator = new ASTORE(ITERATOR_INDEX); _aloadIterator = new ALOAD(ITERATOR_INDEX); _aloadDom = new ALOAD(DOM_INDEX); _astoreDom = new ASTORE(DOM_INDEX); final int startElement = cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, "startElement", START_ELEMENT_SIG); _startElement = new INVOKEINTERFACE(startElement, 2); final int endElement = cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, "endElement", END_ELEMENT_SIG); _endElement = new INVOKEINTERFACE(endElement, 2); final int attribute = cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, "addAttribute", "(" + STRING_SIG + STRING_SIG + ")V"); _attribute = new INVOKEINTERFACE(attribute, 3); final int uniqueAttribute = cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, "addUniqueAttribute", "(" + STRING_SIG + STRING_SIG + "I)V"); _uniqueAttribute = new INVOKEINTERFACE(uniqueAttribute, 4); final int namespace = cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, "namespaceAfterStartElement", "(" + STRING_SIG + STRING_SIG + ")V"); _namespace = new INVOKEINTERFACE(namespace, 3); int index = cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, "startDocument", "()V"); _startDocument = new INVOKEINTERFACE(index, 1); index = cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, "endDocument", "()V"); _endDocument = new INVOKEINTERFACE(index, 1); index = cpg.addInterfaceMethodref(NODE_ITERATOR, SET_START_NODE, SET_START_NODE_SIG); _setStartNode = new INVOKEINTERFACE(index, 2); index = cpg.addInterfaceMethodref(NODE_ITERATOR, "reset", "()"+NODE_ITERATOR_SIG); _reset = new INVOKEINTERFACE(index, 1); index = cpg.addInterfaceMethodref(NODE_ITERATOR, NEXT, NEXT_SIG); _nextNode = new INVOKEINTERFACE(index, 1); _slotAllocator = new SlotAllocator(); _slotAllocator.initialize(getLocalVariables()); _allocatorInit = true; } /** * Allocates a local variable. If the slot allocator has already been * initialized, then call addLocalVariable2() so that the new variable * is known to the allocator. Failing to do this may cause the allocator * to return a slot that is already in use. */ public LocalVariableGen addLocalVariable(String name, Type type, InstructionHandle start, InstructionHandle end) { return (_allocatorInit) ? addLocalVariable2(name, type, start) : super.addLocalVariable(name, type, start, end); } public LocalVariableGen addLocalVariable2(String name, Type type, InstructionHandle start) { return super.addLocalVariable(name, type, _slotAllocator.allocateSlot(type), start, null); } public void removeLocalVariable(LocalVariableGen lvg) { _slotAllocator.releaseSlot(lvg); super.removeLocalVariable(lvg); } public Instruction loadDOM() { return _aloadDom; } public Instruction storeDOM() { return _astoreDom; } public Instruction storeHandler() { return _astoreHandler; } public Instruction loadHandler() { return _aloadHandler; } public Instruction storeIterator() { return _astoreIterator; } public Instruction loadIterator() { return _aloadIterator; } public final Instruction setStartNode() { return _setStartNode; } public final Instruction reset() { return _reset; } public final Instruction nextNode() { return _nextNode; } public final Instruction startElement() { return _startElement; } public final Instruction endElement() { return _endElement; } public final Instruction startDocument() { return _startDocument; } public final Instruction endDocument() { return _endDocument; } public final Instruction attribute() { return _attribute; } public final Instruction uniqueAttribute() { return _uniqueAttribute; } public final Instruction namespace() { return _namespace; } public Instruction loadCurrentNode() { if (_iloadCurrent == null) { int idx = getLocalIndex("current"); if (idx > 0) _iloadCurrent = new ILOAD(idx); else _iloadCurrent = new ICONST(0); } return _iloadCurrent; } public Instruction storeCurrentNode() { return _istoreCurrent != null ? _istoreCurrent : (_istoreCurrent = new ISTORE(getLocalIndex("current"))); } /** by default context node is the same as current node. MK437 */ public Instruction loadContextNode() { return loadCurrentNode(); } public Instruction storeContextNode() { return storeCurrentNode(); } public int getLocalIndex(String name) { return getLocalVariable(name).getIndex(); } public LocalVariableGen getLocalVariable(String name) { final LocalVariableGen[] vars = getLocalVariables(); for (int i = 0; i < vars.length; i++) if (vars[i].getName().equals(name)) return vars[i]; return null; } public void setMaxLocals() { // Get the current number of local variable slots int maxLocals = super.getMaxLocals(); int prevLocals = maxLocals; // Get numer of actual variables final LocalVariableGen[] localVars = super.getLocalVariables(); if (localVars != null) { if (localVars.length > maxLocals) maxLocals = localVars.length; } // We want at least 5 local variable slots (for parameters) if (maxLocals < 5) maxLocals = 5; super.setMaxLocals(maxLocals); } }