001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: RealType.java 468649 2006-10-28 07:00:55Z minchau $ 020 */ 021 022 package org.apache.xalan.xsltc.compiler.util; 023 024 import org.apache.bcel.generic.BranchHandle; 025 import org.apache.bcel.generic.CHECKCAST; 026 import org.apache.bcel.generic.ConstantPoolGen; 027 import org.apache.bcel.generic.DLOAD; 028 import org.apache.bcel.generic.DSTORE; 029 import org.apache.bcel.generic.GOTO; 030 import org.apache.bcel.generic.IFEQ; 031 import org.apache.bcel.generic.IFNE; 032 import org.apache.bcel.generic.INVOKESPECIAL; 033 import org.apache.bcel.generic.INVOKESTATIC; 034 import org.apache.bcel.generic.INVOKEVIRTUAL; 035 import org.apache.bcel.generic.Instruction; 036 import org.apache.bcel.generic.InstructionConstants; 037 import org.apache.bcel.generic.InstructionList; 038 import org.apache.bcel.generic.LocalVariableGen; 039 import org.apache.bcel.generic.NEW; 040 import org.apache.xalan.xsltc.compiler.Constants; 041 import org.apache.xalan.xsltc.compiler.FlowList; 042 043 /** 044 * @author Jacek Ambroziak 045 * @author Santiago Pericas-Geertsen 046 */ 047 public final class RealType extends NumberType { 048 protected RealType() {} 049 050 public String toString() { 051 return "real"; 052 } 053 054 public boolean identicalTo(Type other) { 055 return this == other; 056 } 057 058 public String toSignature() { 059 return "D"; 060 } 061 062 public org.apache.bcel.generic.Type toJCType() { 063 return org.apache.bcel.generic.Type.DOUBLE; 064 } 065 066 /** 067 * @see org.apache.xalan.xsltc.compiler.util.Type#distanceTo 068 */ 069 public int distanceTo(Type type) { 070 if (type == this) { 071 return 0; 072 } 073 else if (type == Type.Int) { 074 return 1; 075 } 076 else { 077 return Integer.MAX_VALUE; 078 } 079 } 080 081 /** 082 * Translates a real into an object of internal type <code>type</code>. The 083 * translation to int is undefined since reals are never converted to ints. 084 * 085 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo 086 */ 087 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 088 Type type) { 089 if (type == Type.String) { 090 translateTo(classGen, methodGen, (StringType) type); 091 } 092 else if (type == Type.Boolean) { 093 translateTo(classGen, methodGen, (BooleanType) type); 094 } 095 else if (type == Type.Reference) { 096 translateTo(classGen, methodGen, (ReferenceType) type); 097 } 098 else if (type == Type.Int) { 099 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 org.apache.xalan.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 org.apache.xalan.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 org.apache.xalan.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 org.apache.xalan.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 org.apache.bcel.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 org.apache.xalan.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 InstructionConstants.DADD; 300 } 301 302 public Instruction SUB() { 303 return InstructionConstants.DSUB; 304 } 305 306 public Instruction MUL() { 307 return InstructionConstants.DMUL; 308 } 309 310 public Instruction DIV() { 311 return InstructionConstants.DDIV; 312 } 313 314 public Instruction REM() { 315 return InstructionConstants.DREM; 316 } 317 318 public Instruction NEG() { 319 return InstructionConstants.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 ? InstructionConstants.DCMPG : InstructionConstants.DCMPL; 336 } 337 338 public Instruction DUP() { 339 return DUP2; 340 } 341 } 342