1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * @LastModified: Oct 2017 4 */ 5 /* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package com.sun.org.apache.xalan.internal.xsltc.compiler.util; 23 24 import com.sun.org.apache.bcel.internal.generic.BranchHandle; 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.DLOAD; 28 import com.sun.org.apache.bcel.internal.generic.DSTORE; 29 import com.sun.org.apache.bcel.internal.generic.GOTO; 30 import com.sun.org.apache.bcel.internal.generic.IFEQ; 31 import com.sun.org.apache.bcel.internal.generic.IFNE; 32 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL; 33 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC; 34 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; 35 import com.sun.org.apache.bcel.internal.generic.Instruction; 36 import com.sun.org.apache.bcel.internal.generic.InstructionConst; 37 import com.sun.org.apache.bcel.internal.generic.InstructionList; 38 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; 39 import com.sun.org.apache.bcel.internal.generic.NEW; 40 import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants; 41 import com.sun.org.apache.xalan.internal.xsltc.compiler.FlowList; 42 43 /** 44 * @author Jacek Ambroziak 45 * @author Santiago Pericas-Geertsen 46 */ 47 public final class RealType extends NumberType { 48 protected RealType() {} 49 50 public String toString() { 51 return "real"; 52 } 53 54 public boolean identicalTo(Type other) { 55 return this == other; 56 } 57 58 public String toSignature() { 59 return "D"; 60 } 61 62 public com.sun.org.apache.bcel.internal.generic.Type toJCType() { 63 return com.sun.org.apache.bcel.internal.generic.Type.DOUBLE; 64 } 65 66 /** 67 * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#distanceTo 68 */ 69 public int distanceTo(Type type) { 70 if (type == this) { 71 return 0; 72 } 73 else if (type == Type.Int) { 74 return 1; 75 } 76 else { 77 return Integer.MAX_VALUE; 78 } 79 } 80 81 /** 82 * Translates a real into an object of internal type <code>type</code>. The 83 * translation to int is undefined since reals are never converted to ints. 84 * 85 * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo 86 */ 87 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 88 Type type) { 89 if (type == Type.String) { 90 translateTo(classGen, methodGen, (StringType) type); 91 } 92 else if (type == Type.Boolean) { 93 translateTo(classGen, methodGen, (BooleanType) type); 94 } 95 else if (type == Type.Reference) { 96 translateTo(classGen, methodGen, (ReferenceType) type); 97 } 98 else if (type == Type.Int) { 99 translateTo(classGen, methodGen, (IntType) type); 100 } 101 else { 102 ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR, 103 toString(), type.toString()); 104 classGen.getParser().reportError(Constants.FATAL, err); 105 } 106 } 107 108 /** 109 * Expects a real on the stack and pushes its string value by calling 110 * <code>Double.toString(double d)</code>. 111 * 112 * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo 113 */ 114 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 115 StringType type) { 116 final ConstantPoolGen cpg = classGen.getConstantPool(); 117 final InstructionList il = methodGen.getInstructionList(); 118 il.append(new INVOKESTATIC(cpg.addMethodref(BASIS_LIBRARY_CLASS, 119 "realToString", 120 "(D)" + STRING_SIG))); 121 } 122 123 /** 124 * Expects a real on the stack and pushes a 0 if that number is 0.0 and 125 * a 1 otherwise. 126 * 127 * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo 128 */ 129 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 130 BooleanType type) { 131 final InstructionList il = methodGen.getInstructionList(); 132 FlowList falsel = translateToDesynthesized(classGen, methodGen, type); 133 il.append(ICONST_1); 134 final BranchHandle truec = il.append(new GOTO(null)); 135 falsel.backPatch(il.append(ICONST_0)); 136 truec.setTarget(il.append(NOP)); 137 } 138 139 /** 140 * Expects a real on the stack and pushes a truncated integer value 141 * 142 * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo 143 */ 144 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 145 IntType type) { 146 final ConstantPoolGen cpg = classGen.getConstantPool(); 147 final InstructionList il = methodGen.getInstructionList(); 148 il.append(new INVOKESTATIC(cpg.addMethodref(BASIS_LIBRARY_CLASS, 149 "realToInt","(D)I"))); 150 } 151 152 /** 153 * Translates a real into a non-synthesized boolean. It does not push a 154 * 0 or a 1 but instead returns branchhandle list to be appended to the 155 * false list. A NaN must be converted to "false". 156 * 157 * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateToDesynthesized 158 */ 159 public FlowList translateToDesynthesized(ClassGenerator classGen, 160 MethodGenerator methodGen, 161 BooleanType type) { 162 LocalVariableGen local; 163 final FlowList flowlist = new FlowList(); 164 final ConstantPoolGen cpg = classGen.getConstantPool(); 165 final InstructionList il = methodGen.getInstructionList(); 166 167 // Store real into a local variable 168 il.append(DUP2); 169 local = methodGen.addLocalVariable("real_to_boolean_tmp", 170 com.sun.org.apache.bcel.internal.generic.Type.DOUBLE, 171 null, null); 172 local.setStart(il.append(new DSTORE(local.getIndex()))); 173 174 // Compare it to 0.0 175 il.append(DCONST_0); 176 il.append(DCMPG); 177 flowlist.add(il.append(new IFEQ(null))); 178 179 //!!! call isNaN 180 // Compare it to itself to see if NaN 181 il.append(new DLOAD(local.getIndex())); 182 local.setEnd(il.append(new DLOAD(local.getIndex()))); 183 il.append(DCMPG); 184 flowlist.add(il.append(new IFNE(null))); // NaN != NaN 185 return flowlist; 186 } 187 188 /** 189 * Expects a double on the stack and pushes a boxed double. Boxed 190 * double are represented by an instance of <code>java.lang.Double</code>. 191 * 192 * @see com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type#translateTo 193 */ 194 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 195 ReferenceType type) { 196 final ConstantPoolGen cpg = classGen.getConstantPool(); 197 final InstructionList il = methodGen.getInstructionList(); 198 il.append(new NEW(cpg.addClass(DOUBLE_CLASS))); 199 il.append(DUP_X2); 200 il.append(DUP_X2); 201 il.append(POP); 202 il.append(new INVOKESPECIAL(cpg.addMethodref(DOUBLE_CLASS, 203 "<init>", "(D)V"))); 204 } 205 206 /** 207 * Translates a real into the Java type denoted by <code>clazz</code>. 208 * Expects a real on the stack and pushes a number of the appropriate 209 * type after coercion. 210 */ 211 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 212 final Class<?> clazz) { 213 final InstructionList il = methodGen.getInstructionList(); 214 if (clazz == Character.TYPE) { 215 il.append(D2I); 216 il.append(I2C); 217 } 218 else if (clazz == Byte.TYPE) { 219 il.append(D2I); 220 il.append(I2B); 221 } 222 else if (clazz == Short.TYPE) { 223 il.append(D2I); 224 il.append(I2S); 225 } 226 else if (clazz == Integer.TYPE) { 227 il.append(D2I); 228 } 229 else if (clazz == Long.TYPE) { 230 il.append(D2L); 231 } 232 else if (clazz == Float.TYPE) { 233 il.append(D2F); 234 } 235 else if (clazz == Double.TYPE) { 236 il.append(NOP); 237 } 238 // Is Double <: clazz? I.e. clazz in { Double, Number, Object } 239 else if (clazz.isAssignableFrom(java.lang.Double.class)) { 240 translateTo(classGen, methodGen, Type.Reference); 241 } 242 else { 243 ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR, 244 toString(), clazz.getName()); 245 classGen.getParser().reportError(Constants.FATAL, err); 246 } 247 } 248 249 /** 250 * Translates an external (primitive) Java type into a real. Expects a java 251 * object on the stack and pushes a real (i.e., a double). 252 */ 253 public void translateFrom(ClassGenerator classGen, MethodGenerator methodGen, 254 Class<?> clazz) { 255 InstructionList il = methodGen.getInstructionList(); 256 257 if (clazz == Character.TYPE || clazz == Byte.TYPE || 258 clazz == Short.TYPE || clazz == Integer.TYPE) { 259 il.append(I2D); 260 } 261 else if (clazz == Long.TYPE) { 262 il.append(L2D); 263 } 264 else if (clazz == Float.TYPE) { 265 il.append(F2D); 266 } 267 else if (clazz == Double.TYPE) { 268 il.append(NOP); 269 } 270 else { 271 ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR, 272 toString(), clazz.getName()); 273 classGen.getParser().reportError(Constants.FATAL, err); 274 } 275 } 276 277 /** 278 * Translates an object of this type to its boxed representation. 279 */ 280 public void translateBox(ClassGenerator classGen, 281 MethodGenerator methodGen) { 282 translateTo(classGen, methodGen, Type.Reference); 283 } 284 285 /** 286 * Translates an object of this type to its unboxed representation. 287 */ 288 public void translateUnBox(ClassGenerator classGen, 289 MethodGenerator methodGen) { 290 final ConstantPoolGen cpg = classGen.getConstantPool(); 291 final InstructionList il = methodGen.getInstructionList(); 292 il.append(new CHECKCAST(cpg.addClass(DOUBLE_CLASS))); 293 il.append(new INVOKEVIRTUAL(cpg.addMethodref(DOUBLE_CLASS, 294 DOUBLE_VALUE, 295 DOUBLE_VALUE_SIG))); 296 } 297 298 public Instruction ADD() { 299 return InstructionConst.DADD; 300 } 301 302 public Instruction SUB() { 303 return InstructionConst.DSUB; 304 } 305 306 public Instruction MUL() { 307 return InstructionConst.DMUL; 308 } 309 310 public Instruction DIV() { 311 return InstructionConst.DDIV; 312 } 313 314 public Instruction REM() { 315 return InstructionConst.DREM; 316 } 317 318 public Instruction NEG() { 319 return InstructionConst.DNEG; 320 } 321 322 public Instruction LOAD(int slot) { 323 return new DLOAD(slot); 324 } 325 326 public Instruction STORE(int slot) { 327 return new DSTORE(slot); 328 } 329 330 public Instruction POP() { 331 return POP2; 332 } 333 334 public Instruction CMP(boolean less) { 335 return less ? InstructionConst.DCMPG : InstructionConst.DCMPL; 336 } 337 338 public Instruction DUP() { 339 return DUP2; 340 } 341 }