001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: ReferenceType.java 468649 2006-10-28 07:00:55Z minchau $
020     */
021    
022    package org.apache.xalan.xsltc.compiler.util;
023    
024    import org.apache.bcel.generic.PUSH;
025    import org.apache.bcel.generic.ALOAD;
026    import org.apache.bcel.generic.ASTORE;
027    import org.apache.bcel.generic.ConstantPoolGen;
028    import org.apache.bcel.generic.IFEQ;
029    import org.apache.bcel.generic.ILOAD;
030    import org.apache.bcel.generic.INVOKEINTERFACE;
031    import org.apache.bcel.generic.INVOKESTATIC;
032    import org.apache.bcel.generic.Instruction;
033    import org.apache.bcel.generic.InstructionList;
034    
035    import org.apache.xalan.xsltc.compiler.Constants;
036    import org.apache.xalan.xsltc.compiler.FlowList;
037    
038    import org.apache.xml.dtm.DTM;
039    
040    /**
041     * @author Jacek Ambroziak
042     * @author Santiago Pericas-Geertsen
043     * @author Erwin Bolwidt <ejb@klomp.org>
044     */
045    public final class ReferenceType extends Type {
046        protected ReferenceType() {}
047    
048        public String toString() {
049            return "reference";
050        }
051    
052        public boolean identicalTo(Type other) {
053            return this == other;
054        }
055    
056        public String toSignature() {
057            return "Ljava/lang/Object;";
058        }
059    
060        public org.apache.bcel.generic.Type toJCType() {
061            return org.apache.bcel.generic.Type.OBJECT;
062        }
063    
064        /**
065         * Translates a reference to an object of internal type <code>type</code>.
066         * The translation to int is undefined since references
067         * are always converted to reals in arithmetic expressions.
068         *
069         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
070         */
071        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
072                                Type type) {
073            if (type == Type.String) {
074                translateTo(classGen, methodGen, (StringType) type);
075            }
076            else if (type == Type.Real) {
077                translateTo(classGen, methodGen, (RealType) type);
078            }
079            else if (type == Type.Boolean) {
080                translateTo(classGen, methodGen, (BooleanType) type);
081            }
082            else if (type == Type.NodeSet) {
083                translateTo(classGen, methodGen, (NodeSetType) type);
084            }
085            else if (type == Type.Node) {
086                translateTo(classGen, methodGen, (NodeType) type);
087            }
088            else if (type == Type.ResultTree) {
089                translateTo(classGen, methodGen, (ResultTreeType) type);
090            }
091            else if (type == Type.Object) {
092                translateTo(classGen, methodGen, (ObjectType) type);
093            }
094            else if (type == Type.Reference ) {
095            }       
096            else {
097                ErrorMsg err = new ErrorMsg(ErrorMsg.INTERNAL_ERR, type.toString());
098                classGen.getParser().reportError(Constants.FATAL, err);
099            }
100        }
101    
102        /**
103         * Translates reference into object of internal type <code>type</code>.
104         *
105         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
106         */
107        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
108                                StringType type) {
109            final int current = methodGen.getLocalIndex("current");
110            ConstantPoolGen cpg = classGen.getConstantPool();
111            InstructionList il = methodGen.getInstructionList();
112    
113            // If no current, conversion is a top-level
114            if (current < 0) {
115                il.append(new PUSH(cpg, DTM.ROOT_NODE));  // push root node
116            }
117            else {
118                il.append(new ILOAD(current));
119            }
120            il.append(methodGen.loadDOM());
121            final int stringF = cpg.addMethodref(BASIS_LIBRARY_CLASS,
122                                                 "stringF",
123                                                 "("
124                                                 + OBJECT_SIG
125                                                 + NODE_SIG
126                                                 + DOM_INTF_SIG
127                                                 + ")" + STRING_SIG);
128            il.append(new INVOKESTATIC(stringF));
129        }
130    
131        /**
132         * Translates a reference into an object of internal type <code>type</code>.
133         *
134         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
135         */
136        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
137                                RealType type) {
138            final ConstantPoolGen cpg = classGen.getConstantPool();
139            final InstructionList il = methodGen.getInstructionList();
140    
141            il.append(methodGen.loadDOM());
142            int index = cpg.addMethodref(BASIS_LIBRARY_CLASS, "numberF",
143                                         "("
144                                         + OBJECT_SIG
145                                         + DOM_INTF_SIG
146                                         + ")D");
147            il.append(new INVOKESTATIC(index));
148        }
149    
150        /**
151         * Translates a reference to an object of internal type <code>type</code>.
152         *
153         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
154         */
155        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
156                                BooleanType type) {
157            final ConstantPoolGen cpg = classGen.getConstantPool();
158            final InstructionList il = methodGen.getInstructionList();
159    
160            int index = cpg.addMethodref(BASIS_LIBRARY_CLASS, "booleanF",
161                                         "("
162                                         + OBJECT_SIG
163                                         + ")Z");
164            il.append(new INVOKESTATIC(index));
165        }
166    
167        /**
168         * Casts a reference into a NodeIterator.
169         *
170         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
171         */
172        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
173                                NodeSetType type) {
174            final ConstantPoolGen cpg = classGen.getConstantPool();
175            final InstructionList il = methodGen.getInstructionList();
176            int index = cpg.addMethodref(BASIS_LIBRARY_CLASS, "referenceToNodeSet",
177                                         "("
178                                         + OBJECT_SIG
179                                         + ")"
180                                         + NODE_ITERATOR_SIG);
181            il.append(new INVOKESTATIC(index));
182    
183            // Reset this iterator
184            index = cpg.addInterfaceMethodref(NODE_ITERATOR, RESET, RESET_SIG);
185            il.append(new INVOKEINTERFACE(index, 1));
186        }
187    
188        /**
189         * Casts a reference into a Node.
190         *
191         * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo
192         */
193        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
194                                NodeType type) {
195            translateTo(classGen, methodGen, Type.NodeSet);
196            Type.NodeSet.translateTo(classGen, methodGen, type);
197        }
198    
199        /**
200         * Casts a reference into a ResultTree.
201         *
202         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
203         */
204        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
205                                ResultTreeType type) {
206            final ConstantPoolGen cpg = classGen.getConstantPool();
207            final InstructionList il = methodGen.getInstructionList();
208            int index = cpg.addMethodref(BASIS_LIBRARY_CLASS, "referenceToResultTree",
209                                         "(" + OBJECT_SIG + ")" + DOM_INTF_SIG);
210            il.append(new INVOKESTATIC(index));
211        }
212    
213        /**
214         * Subsume reference into ObjectType.
215         *
216         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
217         */
218        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
219                                ObjectType type) {
220            methodGen.getInstructionList().append(NOP);
221        }
222    
223        /**
224         * Translates a reference into the Java type denoted by <code>clazz</code>.
225         */
226        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
227                                Class clazz) {
228            final ConstantPoolGen cpg = classGen.getConstantPool();
229            final InstructionList il = methodGen.getInstructionList();
230    
231            int referenceToLong = cpg.addMethodref(BASIS_LIBRARY_CLASS, 
232                                                   "referenceToLong", 
233                                                   "(" + OBJECT_SIG + ")J");
234            int referenceToDouble = cpg.addMethodref(BASIS_LIBRARY_CLASS, 
235                                                     "referenceToDouble", 
236                                                    "(" + OBJECT_SIG + ")D");      
237            int referenceToBoolean = cpg.addMethodref(BASIS_LIBRARY_CLASS, 
238                                                      "referenceToBoolean", 
239                                                     "(" + OBJECT_SIG + ")Z");
240            
241            if (clazz.getName().equals("java.lang.Object")) {
242                il.append(NOP);
243            }
244            else if (clazz == Double.TYPE) {
245                il.append(new INVOKESTATIC(referenceToDouble));
246            }
247            else if (clazz.getName().equals("java.lang.Double")) {
248                il.append(new INVOKESTATIC(referenceToDouble));
249                Type.Real.translateTo(classGen, methodGen, Type.Reference);
250            }
251            else if (clazz == Float.TYPE) {
252                il.append(new INVOKESTATIC(referenceToDouble));
253                il.append(D2F);
254            }
255            else if (clazz.getName().equals("java.lang.String")) {
256                int index = cpg.addMethodref(BASIS_LIBRARY_CLASS, "referenceToString",
257                                             "("
258                                             + OBJECT_SIG
259                                             + DOM_INTF_SIG
260                                             + ")"
261                                             + "Ljava/lang/String;");
262                il.append(methodGen.loadDOM());
263                il.append(new INVOKESTATIC(index));
264            }
265            else if (clazz.getName().equals("org.w3c.dom.Node")) {
266                int index = cpg.addMethodref(BASIS_LIBRARY_CLASS, "referenceToNode",
267                                             "("
268                                             + OBJECT_SIG
269                                             + DOM_INTF_SIG
270                                             + ")"
271                                             + "Lorg/w3c/dom/Node;");
272                il.append(methodGen.loadDOM());
273                il.append(new INVOKESTATIC(index));
274            }
275            else if (clazz.getName().equals("org.w3c.dom.NodeList")) {
276                int index = cpg.addMethodref(BASIS_LIBRARY_CLASS, "referenceToNodeList",
277                                             "("
278                                             + OBJECT_SIG
279                                             + DOM_INTF_SIG
280                                             + ")"
281                                             + "Lorg/w3c/dom/NodeList;");
282                il.append(methodGen.loadDOM());
283                il.append(new INVOKESTATIC(index));
284            }
285            else if (clazz.getName().equals("org.apache.xalan.xsltc.DOM")) {
286                translateTo(classGen, methodGen, Type.ResultTree);
287            }
288            else if (clazz == Long.TYPE) {
289                il.append(new INVOKESTATIC(referenceToLong));
290            }
291            else if (clazz == Integer.TYPE) {
292                il.append(new INVOKESTATIC(referenceToLong));
293                il.append(L2I);
294            }
295            else if (clazz == Short.TYPE) {
296                il.append(new INVOKESTATIC(referenceToLong));
297                il.append(L2I);
298                il.append(I2S);
299            }
300            else if (clazz == Byte.TYPE) {
301                il.append(new INVOKESTATIC(referenceToLong));
302                il.append(L2I);
303                il.append(I2B);
304            }
305            else if (clazz == Character.TYPE) {
306                il.append(new INVOKESTATIC(referenceToLong));
307                il.append(L2I);
308                il.append(I2C);
309            }
310            else if (clazz == java.lang.Boolean.TYPE) {
311                il.append(new INVOKESTATIC(referenceToBoolean));
312            }
313            else if (clazz.getName().equals("java.lang.Boolean")) {
314                il.append(new INVOKESTATIC(referenceToBoolean));
315                Type.Boolean.translateTo(classGen, methodGen, Type.Reference);
316            }
317            else {
318                ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
319                                            toString(), clazz.getName());
320                classGen.getParser().reportError(Constants.FATAL, err);
321            }
322        }
323    
324        /**
325         * Translates an external Java type into a reference. Only conversion
326         * allowed is from java.lang.Object.
327         */
328        public void translateFrom(ClassGenerator classGen, MethodGenerator methodGen,
329                                  Class clazz) {
330            if (clazz.getName().equals("java.lang.Object")) {
331                methodGen.getInstructionList().append(NOP);
332            }
333            else {
334                ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
335                                    toString(), clazz.getName());
336                classGen.getParser().reportError(Constants.FATAL, err);
337            }
338        }
339    
340        /**
341         * Expects a reference on the stack and translates it to a non-synthesized
342         * boolean. It does not push a 0 or a 1 but instead returns branchhandle
343         * list to be appended to the false list.
344         *
345         * @see org.apache.xalan.xsltc.compiler.util.Type#translateToDesynthesized
346         */
347        public FlowList translateToDesynthesized(ClassGenerator classGen,
348                                                 MethodGenerator methodGen,
349                                                 BooleanType type) {
350            InstructionList il = methodGen.getInstructionList();
351            translateTo(classGen, methodGen, type);
352            return new FlowList(il.append(new IFEQ(null)));
353        }
354    
355        /**
356         * Translates an object of this type to its boxed representation.
357         */
358        public void translateBox(ClassGenerator classGen,
359                                 MethodGenerator methodGen) {
360        }
361    
362        /**
363         * Translates an object of this type to its unboxed representation.
364         */
365        public void translateUnBox(ClassGenerator classGen,
366                                   MethodGenerator methodGen) {
367        }
368    
369    
370        public Instruction LOAD(int slot) {
371            return new ALOAD(slot);
372        }
373    
374        public Instruction STORE(int slot) {
375            return new ASTORE(slot);
376        }
377    }
378