1 /*
2 * Copyright (c) 2016, 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;
22
23 import com.sun.org.apache.bcel.internal.generic.CHECKCAST;
24 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
25 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
26 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
27 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
28 import com.sun.org.apache.bcel.internal.generic.Instruction;
29 import com.sun.org.apache.bcel.internal.generic.InstructionList;
30 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
31 import com.sun.org.apache.bcel.internal.generic.NEW;
32 import com.sun.org.apache.bcel.internal.generic.PUSH;
33 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
36 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType;
37 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ResultTreeType;
38 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
39 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
40 import com.sun.org.apache.xml.internal.utils.XML11Char;
41 import java.util.ArrayList;
42 import java.util.List;
43
44 /**
45 * @author Jacek Ambroziak
46 * @author Santiago Pericas-Geertsen
47 * @author Morten Jorgensen
48 * @author Erwin Bolwidt <ejb@klomp.org>
49 * @author John Howard <JohnH@schemasoft.com>
50 * @LastModified: Oct 2017
51 */
52 class VariableBase extends TopLevelElement {
53
54 protected QName _name; // The name of the variable.
55 protected String _escapedName; // The escaped qname of the variable.
56 protected Type _type; // The type of this variable.
57 protected boolean _isLocal; // True if the variable is local.
58 protected LocalVariableGen _local; // Reference to JVM variable
59 protected Instruction _loadInstruction; // Instruction to load JVM variable
60 protected Instruction _storeInstruction; // Instruction to load JVM variable
61 protected Expression _select; // Reference to variable expression
62 protected String select; // Textual repr. of variable expr.
63
64 // References to this variable (when local)
65 protected List<VariableRefBase> _refs = new ArrayList<>(2);
66
67 // Used to make sure parameter field is not added twice
68 protected boolean _ignore = false;
69
70 /**
71 * Disable this variable/parameter
72 */
73 public void disable() {
74 _ignore = true;
75 }
76
77 /**
78 * Add a reference to this variable. Called by VariableRef when an
79 * expression contains a reference to this variable.
80 */
81 public void addReference(VariableRefBase vref) {
82 _refs.add(vref);
83 }
84
85 /**
86 * When a variable is overriden by another, e.g. via xsl:import,
87 * its references need to be copied or otherwise it may be
88 * compiled away as dead code. This method can be used for that
89 * purpose.
90 */
91 public void copyReferences(VariableBase var) {
92 final int size = _refs.size();
93 for (int i = 0; i < size; i++) {
94 var.addReference(_refs.get(i));
95 }
96 }
97
98 /**
99 * Map this variable to a register
100 */
101 public void mapRegister(MethodGenerator methodGen) {
102 if (_local == null) {
103 final InstructionList il = methodGen.getInstructionList();
104 final String name = getEscapedName(); // TODO: namespace ?
105 final com.sun.org.apache.bcel.internal.generic.Type varType = _type.toJCType();
106 _local = methodGen.addLocalVariable2(name, varType, il.getEnd());
107 }
108 }
109
110 /**
111 * Remove the mapping of this variable to a register.
112 * Called when we leave the AST scope of the variable's declaration
113 */
114 public void unmapRegister(ClassGenerator classGen, MethodGenerator methodGen) {
115 if (_local != null) {
116 if (_type instanceof ResultTreeType) {
117 final ConstantPoolGen cpg = classGen.getConstantPool();
118 final InstructionList il = methodGen.getInstructionList();
119 if (classGen.getStylesheet().callsNodeset() && classGen.getDOMClass().equals(MULTI_DOM_CLASS)) {
120 final int removeDA = cpg.addMethodref(MULTI_DOM_CLASS, "removeDOMAdapter", "(" + DOM_ADAPTER_SIG + ")V");
121 il.append(methodGen.loadDOM());
122 il.append(new CHECKCAST(cpg.addClass(MULTI_DOM_CLASS)));
123 il.append(loadInstruction());
124 il.append(new CHECKCAST(cpg.addClass(DOM_ADAPTER_CLASS)));
125 il.append(new INVOKEVIRTUAL(removeDA));
126 }
127 final int release = cpg.addInterfaceMethodref(DOM_IMPL_CLASS, "release", "()V");
128 il.append(loadInstruction());
129 il.append(new INVOKEINTERFACE(release, 1));
130 }
131
132 _local.setEnd(methodGen.getInstructionList().getEnd());
133 methodGen.removeLocalVariable(_local);
134 _refs = null;
135 _local = null;
136 }
137 }
138
139 /**
140 * Returns an instruction for loading the value of this variable onto
141 * the JVM stack.
142 */
143 public Instruction loadInstruction() {
144 if (_loadInstruction == null) {
145 _loadInstruction = _type.LOAD(_local.getIndex());
146 }
147 return _loadInstruction;
148 }
149
150 /**
151 * Returns an instruction for storing a value from the JVM stack
152 * into this variable.
153 */
154 public Instruction storeInstruction() {
155 if (_storeInstruction == null) {
156 _storeInstruction = _type.STORE(_local.getIndex());
157 }
158 return _storeInstruction;
159 }
160
161 /**
162 * Returns the expression from this variable's select attribute (if any)
163 */
164 public Expression getExpression() {
165 return(_select);
166 }
167
168 /**
169 * Display variable as single string
170 */
171 public String toString() {
172 return("variable("+_name+")");
173 }
174
175 /**
176 * Display variable in a full AST dump
177 */
178 public void display(int indent) {
179 indent(indent);
180 System.out.println("Variable " + _name);
181 if (_select != null) {
182 indent(indent + IndentIncrement);
183 System.out.println("select " + _select.toString());
184 }
185 displayContents(indent + IndentIncrement);
186 }
187
188 /**
189 * Returns the type of the variable
190 */
191 public Type getType() {
192 return _type;
193 }
194
195 /**
196 * Returns the name of the variable or parameter as it will occur in the
197 * compiled translet.
198 */
199 public QName getName() {
200 return _name;
201 }
202
203 /**
204 * Returns the escaped qname of the variable or parameter
205 */
206 public String getEscapedName() {
207 return _escapedName;
208 }
209
210 /**
211 * Set the name of the variable or paremeter. Escape all special chars.
212 */
213 public void setName(QName name) {
214 _name = name;
215 _escapedName = Util.escape(name.getStringRep());
216 }
217
218 /**
219 * Returns the true if the variable is local
220 */
221 public boolean isLocal() {
222 return _isLocal;
223 }
224
225 /**
226 * Parse the contents of the <xsl:decimal-format> element.
227 */
228 public void parseContents(Parser parser) {
229 // Get the 'name attribute
230 String name = getAttribute("name");
231
232 if (name.length() > 0) {
233 if (!XML11Char.isXML11ValidQName(name)) {
234 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, name, this);
235 parser.reportError(Constants.ERROR, err);
236 }
237 setName(parser.getQNameIgnoreDefaultNs(name));
238 }
239 else
240 reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "name");
241
242 // Check whether variable/param of the same name is already in scope
243 VariableBase other = parser.lookupVariable(_name);
244 if ((other != null) && (other.getParent() == getParent())) {
245 reportError(this, parser, ErrorMsg.VARIABLE_REDEF_ERR, name);
246 }
247
248 select = getAttribute("select");
249 if (select.length() > 0) {
250 _select = getParser().parseExpression(this, "select", null);
251 if (_select.isDummy()) {
252 reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "select");
253 return;
254 }
255 }
256
257 // Children must be parsed first -> static scoping
258 parseChildren(parser);
259 }
260
261 /**
262 * Compile the value of the variable, which is either in an expression in
263 * a 'select' attribute, or in the variable elements body
264 */
265 public void translateValue(ClassGenerator classGen,
266 MethodGenerator methodGen) {
267 // Compile expression is 'select' attribute if present
268 if (_select != null) {
269 _select.translate(classGen, methodGen);
270 // Create a CachedNodeListIterator for select expressions
271 // in a variable or parameter.
272 if (_select.getType() instanceof NodeSetType) {
273 final ConstantPoolGen cpg = classGen.getConstantPool();
274 final InstructionList il = methodGen.getInstructionList();
275
276 final int initCNI = cpg.addMethodref(CACHED_NODE_LIST_ITERATOR_CLASS,
277 "<init>",
278 "("
279 +NODE_ITERATOR_SIG
280 +")V");
281 il.append(new NEW(cpg.addClass(CACHED_NODE_LIST_ITERATOR_CLASS)));
282 il.append(DUP_X1);
283 il.append(SWAP);
284
285 il.append(new INVOKESPECIAL(initCNI));
286 }
287 _select.startIterator(classGen, methodGen);
288 }
289 // If not, compile result tree from parameter body if present.
290 else if (hasContents()) {
291 compileResultTree(classGen, methodGen);
292 }
293 // If neither are present then store empty string in variable
294 else {
295 final ConstantPoolGen cpg = classGen.getConstantPool();
296 final InstructionList il = methodGen.getInstructionList();
297 il.append(new PUSH(cpg, Constants.EMPTYSTRING));
298 }
299 }
300
301 }
--- EOF ---