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 }