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.ALOAD; 24 import com.sun.org.apache.bcel.internal.generic.ASTORE; 25 import com.sun.org.apache.bcel.internal.generic.CHECKCAST; 26 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; 27 import com.sun.org.apache.bcel.internal.generic.GETFIELD; 28 import com.sun.org.apache.bcel.internal.generic.IFEQ; 29 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; 30 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL; 31 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; 32 import com.sun.org.apache.bcel.internal.generic.Instruction; 33 import com.sun.org.apache.bcel.internal.generic.InstructionList; 34 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; 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 40 /** 41 * @author Jacek Ambroziak 42 * @author Santiago Pericas-Geertsen 43 * @author Morten Jorgensen 44 * @LastModified: Oct 2017 45 */ 46 public final class ResultTreeType extends Type { 47 private final String _methodName; 48 ResultTreeType()49 protected ResultTreeType() { 50 _methodName = null; 51 } 52 ResultTreeType(String methodName)53 public ResultTreeType(String methodName) { 54 _methodName = methodName; 55 } 56 toString()57 public String toString() { 58 return "result-tree"; 59 } 60 identicalTo(Type other)61 public boolean identicalTo(Type other) { 62 return (other instanceof ResultTreeType); 63 } 64 toSignature()65 public String toSignature() { 66 return DOM_INTF_SIG; 67 } 68 toJCType()69 public com.sun.org.apache.bcel.internal.generic.Type toJCType() { 70 return Util.getJCRefType(toSignature()); 71 } 72 getMethodName()73 public String getMethodName() { 74 return _methodName; 75 } 76 implementedAsMethod()77 public boolean implementedAsMethod() { 78 return _methodName != null; 79 } 80 81 /** 82 * Translates a result tree to object of internal type <code>type</code>. 83 * The translation to int is undefined since result trees 84 * are always converted to reals in arithmetic expressions. 85 * 86 * @param classGen A BCEL class generator 87 * @param methodGen A BCEL method generator 88 * @param type An instance of the type to translate the result tree to 89 * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo 90 */ translateTo(ClassGenerator classGen, MethodGenerator methodGen, Type type)91 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 92 Type type) { 93 if (type == Type.String) { 94 translateTo(classGen, methodGen, (StringType)type); 95 } 96 else if (type == Type.Boolean) { 97 translateTo(classGen, methodGen, (BooleanType)type); 98 } 99 else if (type == Type.Real) { 100 translateTo(classGen, methodGen, (RealType)type); 101 } 102 else if (type == Type.NodeSet) { 103 translateTo(classGen, methodGen, (NodeSetType)type); 104 } 105 else if (type == Type.Reference) { 106 translateTo(classGen, methodGen, (ReferenceType)type); 107 } 108 else if (type == Type.Object) { 109 translateTo(classGen, methodGen, (ObjectType) type); 110 } 111 else { 112 ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR, 113 toString(), type.toString()); 114 classGen.getParser().reportError(Constants.FATAL, err); 115 } 116 } 117 118 /** 119 * Expects an result tree on the stack and pushes a boolean. 120 * Translates a result tree to a boolean by first converting it to string. 121 * 122 * @param classGen A BCEL class generator 123 * @param methodGen A BCEL method generator 124 * @param type An instance of BooleanType (any) 125 * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo 126 */ translateTo(ClassGenerator classGen, MethodGenerator methodGen, BooleanType type)127 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 128 BooleanType type) { 129 // A result tree is always 'true' when converted to a boolean value, 130 // since the tree always has at least one node (the root). 131 final ConstantPoolGen cpg = classGen.getConstantPool(); 132 final InstructionList il = methodGen.getInstructionList(); 133 il.append(POP); // don't need the DOM reference 134 il.append(ICONST_1); // push 'true' on the stack 135 } 136 137 /** 138 * Expects an result tree on the stack and pushes a string. 139 * 140 * @param classGen A BCEL class generator 141 * @param methodGen A BCEL method generator 142 * @param type An instance of StringType (any) 143 * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo 144 */ translateTo(ClassGenerator classGen, MethodGenerator methodGen, StringType type)145 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 146 StringType type) { 147 final ConstantPoolGen cpg = classGen.getConstantPool(); 148 final InstructionList il = methodGen.getInstructionList(); 149 150 if (_methodName == null) { 151 int index = cpg.addInterfaceMethodref(DOM_INTF, 152 "getStringValue", 153 "()"+STRING_SIG); 154 il.append(new INVOKEINTERFACE(index, 1)); 155 } 156 else { 157 final String className = classGen.getClassName(); 158 final int current = methodGen.getLocalIndex("current"); 159 160 // Push required parameters 161 il.append(classGen.loadTranslet()); 162 if (classGen.isExternal()) { 163 il.append(new CHECKCAST(cpg.addClass(className))); 164 } 165 il.append(DUP); 166 il.append(new GETFIELD(cpg.addFieldref(className, "_dom", 167 DOM_INTF_SIG))); 168 169 // Create a new instance of a StringValueHandler 170 int index = cpg.addMethodref(STRING_VALUE_HANDLER, "<init>", "()V"); 171 il.append(new NEW(cpg.addClass(STRING_VALUE_HANDLER))); 172 il.append(DUP); 173 il.append(DUP); 174 il.append(new INVOKESPECIAL(index)); 175 176 // Store new Handler into a local variable 177 final LocalVariableGen handler = 178 methodGen.addLocalVariable("rt_to_string_handler", 179 Util.getJCRefType(STRING_VALUE_HANDLER_SIG), 180 null, null); 181 handler.setStart(il.append(new ASTORE(handler.getIndex()))); 182 183 // Call the method that implements this result tree 184 index = cpg.addMethodref(className, _methodName, 185 "("+DOM_INTF_SIG+TRANSLET_OUTPUT_SIG+")V"); 186 il.append(new INVOKEVIRTUAL(index)); 187 188 // Restore new handler and call getValue() 189 handler.setEnd(il.append(new ALOAD(handler.getIndex()))); 190 index = cpg.addMethodref(STRING_VALUE_HANDLER, 191 "getValue", 192 "()" + STRING_SIG); 193 il.append(new INVOKEVIRTUAL(index)); 194 } 195 } 196 197 /** 198 * Expects an result tree on the stack and pushes a real. 199 * Translates a result tree into a real by first converting it to string. 200 * 201 * @param classGen A BCEL class generator 202 * @param methodGen A BCEL method generator 203 * @param type An instance of RealType (any) 204 * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo 205 */ translateTo(ClassGenerator classGen, MethodGenerator methodGen, RealType type)206 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 207 RealType type) { 208 translateTo(classGen, methodGen, Type.String); 209 Type.String.translateTo(classGen, methodGen, Type.Real); 210 } 211 212 /** 213 * Expects a result tree on the stack and pushes a boxed result tree. 214 * Result trees are already boxed so the translation is just a NOP. 215 * 216 * @param classGen A BCEL class generator 217 * @param methodGen A BCEL method generator 218 * @param type An instance of ReferenceType (any) 219 * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo 220 */ translateTo(ClassGenerator classGen, MethodGenerator methodGen, ReferenceType type)221 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 222 ReferenceType type) { 223 final ConstantPoolGen cpg = classGen.getConstantPool(); 224 final InstructionList il = methodGen.getInstructionList(); 225 226 if (_methodName == null) { 227 il.append(NOP); 228 } 229 else { 230 LocalVariableGen domBuilder, newDom; 231 final String className = classGen.getClassName(); 232 final int current = methodGen.getLocalIndex("current"); 233 234 // Push required parameters 235 il.append(classGen.loadTranslet()); 236 if (classGen.isExternal()) { 237 il.append(new CHECKCAST(cpg.addClass(className))); 238 } 239 il.append(methodGen.loadDOM()); 240 241 // Create new instance of DOM class (with RTF_INITIAL_SIZE nodes) 242 il.append(methodGen.loadDOM()); 243 int index = cpg.addInterfaceMethodref(DOM_INTF, 244 "getResultTreeFrag", 245 "(IZ)" + DOM_INTF_SIG); 246 il.append(new PUSH(cpg, RTF_INITIAL_SIZE)); 247 il.append(new PUSH(cpg, false)); 248 il.append(new INVOKEINTERFACE(index,3)); 249 il.append(DUP); 250 251 // Store new DOM into a local variable 252 newDom = methodGen.addLocalVariable("rt_to_reference_dom", 253 Util.getJCRefType(DOM_INTF_SIG), 254 null, null); 255 il.append(new CHECKCAST(cpg.addClass(DOM_INTF_SIG))); 256 newDom.setStart(il.append(new ASTORE(newDom.getIndex()))); 257 258 // Overwrite old handler with DOM handler 259 index = cpg.addInterfaceMethodref(DOM_INTF, 260 "getOutputDomBuilder", 261 "()" + TRANSLET_OUTPUT_SIG); 262 263 il.append(new INVOKEINTERFACE(index,1)); 264 //index = cpg.addMethodref(DOM_IMPL, 265 // "getOutputDomBuilder", 266 // "()" + TRANSLET_OUTPUT_SIG); 267 //il.append(new INVOKEVIRTUAL(index)); 268 il.append(DUP); 269 il.append(DUP); 270 271 // Store DOM handler in a local in order to call endDocument() 272 domBuilder = 273 methodGen.addLocalVariable("rt_to_reference_handler", 274 Util.getJCRefType(TRANSLET_OUTPUT_SIG), 275 null, null); 276 domBuilder.setStart(il.append(new ASTORE(domBuilder.getIndex()))); 277 278 // Call startDocument on the new handler 279 index = cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, 280 "startDocument", "()V"); 281 il.append(new INVOKEINTERFACE(index, 1)); 282 283 // Call the method that implements this result tree 284 index = cpg.addMethodref(className, 285 _methodName, 286 "(" 287 + DOM_INTF_SIG 288 + TRANSLET_OUTPUT_SIG 289 +")V"); 290 il.append(new INVOKEVIRTUAL(index)); 291 292 // Call endDocument on the DOM handler 293 domBuilder.setEnd(il.append(new ALOAD(domBuilder.getIndex()))); 294 index = cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, 295 "endDocument", "()V"); 296 il.append(new INVOKEINTERFACE(index, 1)); 297 298 // Push the new DOM on the stack 299 newDom.setEnd(il.append(new ALOAD(newDom.getIndex()))); 300 } 301 } 302 303 /** 304 * Expects a result tree on the stack and pushes a node-set (iterator). 305 * Note that the produced iterator is an iterator for the DOM that 306 * contains the result tree, and not the DOM that is currently in use. 307 * This conversion here will therefore not directly work with elements 308 * such as <xsl:apply-templates> and <xsl:for-each> without the DOM 309 * parameter/variable being updates as well. 310 * 311 * @param classGen A BCEL class generator 312 * @param methodGen A BCEL method generator 313 * @param type An instance of NodeSetType (any) 314 * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo 315 */ translateTo(ClassGenerator classGen, MethodGenerator methodGen, NodeSetType type)316 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 317 NodeSetType type) { 318 final ConstantPoolGen cpg = classGen.getConstantPool(); 319 final InstructionList il = methodGen.getInstructionList(); 320 321 // Put an extra copy of the result tree (DOM) on the stack 322 il.append(DUP); 323 324 // DOM adapters containing a result tree are not initialised with 325 // translet-type to DOM-type mapping. This must be done now for 326 // XPath expressions and patterns to work for the iterator we create. 327 il.append(classGen.loadTranslet()); // get names array 328 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS, 329 NAMES_INDEX, 330 NAMES_INDEX_SIG))); 331 il.append(classGen.loadTranslet()); // get uris array 332 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS, 333 URIS_INDEX, 334 URIS_INDEX_SIG))); 335 il.append(classGen.loadTranslet()); // get types array 336 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS, 337 TYPES_INDEX, 338 TYPES_INDEX_SIG))); 339 il.append(classGen.loadTranslet()); // get namespaces array 340 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS, 341 NAMESPACE_INDEX, 342 NAMESPACE_INDEX_SIG))); 343 // Pass the type mappings to the DOM adapter 344 final int mapping = cpg.addInterfaceMethodref(DOM_INTF, 345 "setupMapping", 346 "(["+STRING_SIG+ 347 "["+STRING_SIG+ 348 "[I" + 349 "["+STRING_SIG+")V"); 350 il.append(new INVOKEINTERFACE(mapping, 5)); 351 il.append(DUP); 352 353 // Create an iterator for the root node of the DOM adapter 354 final int iter = cpg.addInterfaceMethodref(DOM_INTF, 355 "getIterator", 356 "()"+NODE_ITERATOR_SIG); 357 il.append(new INVOKEINTERFACE(iter, 1)); 358 } 359 360 /** 361 * Subsume result tree into ObjectType. 362 * 363 * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo 364 */ translateTo(ClassGenerator classGen, MethodGenerator methodGen, ObjectType type)365 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 366 ObjectType type) { 367 methodGen.getInstructionList().append(NOP); 368 } 369 370 /** 371 * Translates a result tree into a non-synthesized boolean. 372 * It does not push a 0 or a 1 but instead returns branchhandle list 373 * to be appended to the false list. 374 * 375 * @param classGen A BCEL class generator 376 * @param methodGen A BCEL method generator 377 * @param type An instance of BooleanType (any) 378 * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateToDesynthesized 379 */ translateToDesynthesized(ClassGenerator classGen, MethodGenerator methodGen, BooleanType type)380 public FlowList translateToDesynthesized(ClassGenerator classGen, 381 MethodGenerator methodGen, 382 BooleanType type) { 383 final InstructionList il = methodGen.getInstructionList(); 384 translateTo(classGen, methodGen, Type.Boolean); 385 return new FlowList(il.append(new IFEQ(null))); 386 } 387 388 /** 389 * Translates a result tree to a Java type denoted by <code>clazz</code>. 390 * Expects a result tree on the stack and pushes an object 391 * of the appropriate type after coercion. Result trees are translated 392 * to W3C Node or W3C NodeList and the translation is done 393 * via node-set type. 394 * 395 * @param classGen A BCEL class generator 396 * @param methodGen A BCEL method generator 397 * @param clazz An reference to the Class to translate to 398 * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo 399 */ translateTo(ClassGenerator classGen, MethodGenerator methodGen, Class<?> clazz)400 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 401 Class<?> clazz) { 402 final String className = clazz.getName(); 403 final ConstantPoolGen cpg = classGen.getConstantPool(); 404 final InstructionList il = methodGen.getInstructionList(); 405 406 if (className.equals("org.w3c.dom.Node")) { 407 translateTo(classGen, methodGen, Type.NodeSet); 408 int index = cpg.addInterfaceMethodref(DOM_INTF, 409 MAKE_NODE, 410 MAKE_NODE_SIG2); 411 il.append(new INVOKEINTERFACE(index, 2)); 412 } 413 else if (className.equals("org.w3c.dom.NodeList")) { 414 translateTo(classGen, methodGen, Type.NodeSet); 415 int index = cpg.addInterfaceMethodref(DOM_INTF, 416 MAKE_NODE_LIST, 417 MAKE_NODE_LIST_SIG2); 418 il.append(new INVOKEINTERFACE(index, 2)); 419 } 420 else if (className.equals("java.lang.Object")) { 421 il.append(NOP); 422 } 423 else if (className.equals("java.lang.String")) { 424 translateTo(classGen, methodGen, Type.String); 425 } 426 else { 427 ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR, 428 toString(), className); 429 classGen.getParser().reportError(Constants.FATAL, err); 430 } 431 } 432 433 /** 434 * Translates an object of this type to its boxed representation. 435 */ translateBox(ClassGenerator classGen, MethodGenerator methodGen)436 public void translateBox(ClassGenerator classGen, 437 MethodGenerator methodGen) { 438 translateTo(classGen, methodGen, Type.Reference); 439 } 440 441 /** 442 * Translates an object of this type to its unboxed representation. 443 */ translateUnBox(ClassGenerator classGen, MethodGenerator methodGen)444 public void translateUnBox(ClassGenerator classGen, 445 MethodGenerator methodGen) { 446 methodGen.getInstructionList().append(NOP); 447 } 448 449 /** 450 * Returns the class name of an internal type's external representation. 451 */ getClassName()452 public String getClassName() { 453 return(DOM_INTF); 454 } 455 LOAD(int slot)456 public Instruction LOAD(int slot) { 457 return new ALOAD(slot); 458 } 459 STORE(int slot)460 public Instruction STORE(int slot) { 461 return new ASTORE(slot); 462 } 463 } 464