1 /*
2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
3  */
4 /*
5  * Licensed to the Apache Software Foundation (ASF) under one or more
6  * contributor license agreements.  See the NOTICE file distributed with
7  * this work for additional information regarding copyright ownership.
8  * The ASF licenses this file to You under the Apache License, Version 2.0
9  * (the "License"); you may not use this file except in compliance with
10  * the License.  You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 package com.sun.org.apache.xalan.internal.xsltc.compiler.util;
22 
23 import com.sun.org.apache.bcel.internal.generic.BranchHandle;
24 import com.sun.org.apache.bcel.internal.generic.CHECKCAST;
25 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
26 import com.sun.org.apache.bcel.internal.generic.GETFIELD;
27 import com.sun.org.apache.bcel.internal.generic.GOTO;
28 import com.sun.org.apache.bcel.internal.generic.IFEQ;
29 import com.sun.org.apache.bcel.internal.generic.ILOAD;
30 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
31 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
32 import com.sun.org.apache.bcel.internal.generic.ISTORE;
33 import com.sun.org.apache.bcel.internal.generic.Instruction;
34 import com.sun.org.apache.bcel.internal.generic.InstructionList;
35 import com.sun.org.apache.bcel.internal.generic.NEW;
36 import com.sun.org.apache.bcel.internal.generic.PUSH;
37 import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants;
38 import com.sun.org.apache.xalan.internal.xsltc.compiler.FlowList;
39 import com.sun.org.apache.xalan.internal.xsltc.compiler.NodeTest;
40 
41 /**
42  * @author Jacek Ambroziak
43  * @author Santiago Pericas-Geertsen
44  * @LastModified: Oct 2017
45  */
46 public final class NodeType extends Type {
47     private final int _type;
48 
NodeType()49     protected NodeType() {
50         this(NodeTest.ANODE);
51     }
52 
NodeType(int type)53     protected NodeType(int type) {
54         _type = type;
55     }
56 
getType()57     public int getType() {
58         return _type;
59     }
60 
toString()61     public String toString() {
62         return "node-type";
63     }
64 
identicalTo(Type other)65     public boolean identicalTo(Type other) {
66         return other instanceof NodeType;
67     }
68 
hashCode()69     public int hashCode() {
70         return _type;
71     }
72 
toSignature()73     public String toSignature() {
74         return "I";
75     }
76 
toJCType()77     public com.sun.org.apache.bcel.internal.generic.Type toJCType() {
78         return com.sun.org.apache.bcel.internal.generic.Type.INT;
79     }
80 
81     /**
82      * Translates a node into an object of internal type <code>type</code>.
83      * The translation to int is undefined since nodes are always converted
84      * to reals in arithmetic expressions.
85      *
86      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
87      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, Type type)88     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
89                             Type type) {
90         if (type == Type.String) {
91             translateTo(classGen, methodGen, (StringType) type);
92         }
93         else if (type == Type.Boolean) {
94             translateTo(classGen, methodGen, (BooleanType) type);
95         }
96         else if (type == Type.Real) {
97             translateTo(classGen, methodGen, (RealType) type);
98         }
99         else if (type == Type.NodeSet) {
100             translateTo(classGen, methodGen, (NodeSetType) type);
101         }
102         else if (type == Type.Reference) {
103             translateTo(classGen, methodGen, (ReferenceType) type);
104         }
105         else if (type == Type.Object) {
106             translateTo(classGen, methodGen, (ObjectType) type);
107         }
108         else {
109             ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
110                                         toString(), type.toString());
111             classGen.getParser().reportError(Constants.FATAL, err);
112         }
113     }
114 
115     /**
116      * Expects a node on the stack and pushes its string value.
117      *
118      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
119      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, StringType type)120     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
121                             StringType type) {
122         final ConstantPoolGen cpg = classGen.getConstantPool();
123         final InstructionList il = methodGen.getInstructionList();
124 
125         switch (_type) {
126         case NodeTest.ROOT:
127         case NodeTest.ELEMENT:
128             il.append(methodGen.loadDOM());
129             il.append(SWAP); // dom ref must be below node index
130             int index = cpg.addInterfaceMethodref(DOM_INTF,
131                                                   GET_ELEMENT_VALUE,
132                                                   GET_ELEMENT_VALUE_SIG);
133             il.append(new INVOKEINTERFACE(index, 2));
134             break;
135 
136         case NodeTest.ANODE:
137         case NodeTest.COMMENT:
138         case NodeTest.ATTRIBUTE:
139         case NodeTest.PI:
140             il.append(methodGen.loadDOM());
141             il.append(SWAP); // dom ref must be below node index
142             index = cpg.addInterfaceMethodref(DOM_INTF,
143                                               GET_NODE_VALUE,
144                                               GET_NODE_VALUE_SIG);
145             il.append(new INVOKEINTERFACE(index, 2));
146             break;
147 
148         default:
149             ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
150                                         toString(), type.toString());
151             classGen.getParser().reportError(Constants.FATAL, err);
152             break;
153         }
154     }
155 
156     /**
157      * Translates a node into a synthesized boolean.
158      * If the expression is "@attr",
159      * then "true" is pushed iff "attr" is an attribute of the current node.
160      * If the expression is ".", the result is always "true".
161      *
162      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
163      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, BooleanType type)164     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
165                             BooleanType type) {
166         final InstructionList il = methodGen.getInstructionList();
167         FlowList falsel = translateToDesynthesized(classGen, methodGen, type);
168         il.append(ICONST_1);
169         final BranchHandle truec = il.append(new GOTO(null));
170         falsel.backPatch(il.append(ICONST_0));
171         truec.setTarget(il.append(NOP));
172     }
173 
174     /**
175      * Expects a node on the stack and pushes a real.
176      * First the node is converted to string, and from string to real.
177      *
178      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
179      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, RealType type)180     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
181                             RealType type) {
182         translateTo(classGen, methodGen, Type.String);
183         Type.String.translateTo(classGen, methodGen, Type.Real);
184     }
185 
186     /**
187      * Expects a node on the stack and pushes a singleton node-set. Singleton
188      * iterators are already started after construction.
189      *
190      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
191      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, NodeSetType type)192     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
193                             NodeSetType type) {
194         ConstantPoolGen cpg = classGen.getConstantPool();
195         InstructionList il = methodGen.getInstructionList();
196 
197         // Create a new instance of SingletonIterator
198         il.append(new NEW(cpg.addClass(SINGLETON_ITERATOR)));
199         il.append(DUP_X1);
200         il.append(SWAP);
201         final int init = cpg.addMethodref(SINGLETON_ITERATOR, "<init>",
202                                           "(" + NODE_SIG +")V");
203         il.append(new INVOKESPECIAL(init));
204     }
205 
206     /**
207      * Subsume Node into ObjectType.
208      *
209      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
210      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, ObjectType type)211     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
212                             ObjectType type) {
213             methodGen.getInstructionList().append(NOP);
214     }
215 
216     /**
217      * Translates a node into a non-synthesized boolean. It does not push a
218      * 0 or a 1 but instead returns branchhandle list to be appended to the
219      * false list.
220      *
221      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateToDesynthesized
222      */
translateToDesynthesized(ClassGenerator classGen, MethodGenerator methodGen, BooleanType type)223     public FlowList translateToDesynthesized(ClassGenerator classGen,
224                                              MethodGenerator methodGen,
225                                              BooleanType type) {
226         final InstructionList il = methodGen.getInstructionList();
227         return new FlowList(il.append(new IFEQ(null)));
228     }
229 
230     /**
231      * Expects a node on the stack and pushes a boxed node. Boxed nodes
232      * are represented by an instance of <code>com.sun.org.apache.xalan.internal.xsltc.dom.Node</code>.
233      *
234      * @see     com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo
235      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, ReferenceType type)236     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
237                             ReferenceType type) {
238         final ConstantPoolGen cpg = classGen.getConstantPool();
239         final InstructionList il = methodGen.getInstructionList();
240         il.append(new NEW(cpg.addClass(RUNTIME_NODE_CLASS)));
241         il.append(DUP_X1);
242         il.append(SWAP);
243         il.append(new PUSH(cpg, _type));
244         il.append(new INVOKESPECIAL(cpg.addMethodref(RUNTIME_NODE_CLASS,
245                                                      "<init>", "(II)V")));
246     }
247 
248     /**
249      * Translates a node into the Java type denoted by <code>clazz</code>.
250      * Expects a node on the stack and pushes an object of the appropriate
251      * type after coercion.
252      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, Class<?> clazz)253     public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
254                             Class<?> clazz) {
255         final ConstantPoolGen cpg = classGen.getConstantPool();
256         final InstructionList il = methodGen.getInstructionList();
257 
258         String className = clazz.getName();
259         if (className.equals("java.lang.String")) {
260            translateTo(classGen, methodGen, Type.String);
261            return;
262         }
263 
264         il.append(methodGen.loadDOM());
265         il.append(SWAP);                // dom ref must be below node index
266 
267         if (className.equals("org.w3c.dom.Node") ||
268             className.equals("java.lang.Object")) {
269             int index = cpg.addInterfaceMethodref(DOM_INTF,
270                                                   MAKE_NODE,
271                                                   MAKE_NODE_SIG);
272             il.append(new INVOKEINTERFACE(index, 2));
273         }
274         else if (className.equals("org.w3c.dom.NodeList")) {
275             int index = cpg.addInterfaceMethodref(DOM_INTF,
276                                                   MAKE_NODE_LIST,
277                                                   MAKE_NODE_LIST_SIG);
278             il.append(new INVOKEINTERFACE(index, 2));
279         }
280         else {
281             ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
282                                         toString(), className);
283             classGen.getParser().reportError(Constants.FATAL, err);
284         }
285     }
286 
287     /**
288      * Translates an object of this type to its boxed representation.
289      */
translateBox(ClassGenerator classGen, MethodGenerator methodGen)290     public void translateBox(ClassGenerator classGen,
291                              MethodGenerator methodGen) {
292         translateTo(classGen, methodGen, Type.Reference);
293     }
294 
295     /**
296      * Translates an object of this type to its unboxed representation.
297      */
translateUnBox(ClassGenerator classGen, MethodGenerator methodGen)298     public void translateUnBox(ClassGenerator classGen,
299                                MethodGenerator methodGen) {
300         final ConstantPoolGen cpg = classGen.getConstantPool();
301         final InstructionList il = methodGen.getInstructionList();
302         il.append(new CHECKCAST(cpg.addClass(RUNTIME_NODE_CLASS)));
303         il.append(new GETFIELD(cpg.addFieldref(RUNTIME_NODE_CLASS,
304                                                NODE_FIELD,
305                                                NODE_FIELD_SIG)));
306     }
307 
308     /**
309      * Returns the class name of an internal type's external representation.
310      */
getClassName()311     public String getClassName() {
312         return(RUNTIME_NODE_CLASS);
313     }
314 
LOAD(int slot)315     public Instruction LOAD(int slot) {
316         return new ILOAD(slot);
317     }
318 
STORE(int slot)319     public Instruction STORE(int slot) {
320         return new ISTORE(slot);
321     }
322 }
323