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