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 
21 package com.sun.org.apache.xalan.internal.xsltc.compiler.util;
22 
23 import com.sun.org.apache.bcel.internal.generic.BranchHandle;
24 import com.sun.org.apache.bcel.internal.generic.CHECKCAST;
25 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
26 import com.sun.org.apache.bcel.internal.generic.DLOAD;
27 import com.sun.org.apache.bcel.internal.generic.DSTORE;
28 import com.sun.org.apache.bcel.internal.generic.GOTO;
29 import com.sun.org.apache.bcel.internal.generic.IFEQ;
30 import com.sun.org.apache.bcel.internal.generic.IFNE;
31 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
32 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
33 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
34 import com.sun.org.apache.bcel.internal.generic.Instruction;
35 import com.sun.org.apache.bcel.internal.generic.InstructionConst;
36 import com.sun.org.apache.bcel.internal.generic.InstructionList;
37 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
38 import com.sun.org.apache.bcel.internal.generic.NEW;
39 import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants;
40 import com.sun.org.apache.xalan.internal.xsltc.compiler.FlowList;
41 
42 /**
43  * @author Jacek Ambroziak
44  * @author Santiago Pericas-Geertsen
45  * @LastModified: Oct 2017
46  */
47 public final class RealType extends NumberType {
RealType()48     protected RealType() {}
49 
toString()50     public String toString() {
51         return "real";
52     }
53 
identicalTo(Type other)54     public boolean identicalTo(Type other) {
55         return this == other;
56     }
57 
toSignature()58     public String toSignature() {
59         return "D";
60     }
61 
toJCType()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      */
distanceTo(Type type)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      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, Type type)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      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, StringType type)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      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, BooleanType type)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      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, IntType type)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      */
translateToDesynthesized(ClassGenerator classGen, MethodGenerator methodGen, BooleanType type)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      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, ReferenceType type)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      */
translateTo(ClassGenerator classGen, MethodGenerator methodGen, final Class<?> clazz)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      */
translateFrom(ClassGenerator classGen, MethodGenerator methodGen, Class<?> clazz)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      */
translateBox(ClassGenerator classGen, MethodGenerator methodGen)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      */
translateUnBox(ClassGenerator classGen, MethodGenerator methodGen)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 
ADD()298     public Instruction ADD() {
299         return InstructionConst.DADD;
300     }
301 
SUB()302     public Instruction SUB() {
303         return InstructionConst.DSUB;
304     }
305 
MUL()306     public Instruction MUL() {
307         return InstructionConst.DMUL;
308     }
309 
DIV()310     public Instruction DIV() {
311         return InstructionConst.DDIV;
312     }
313 
REM()314     public Instruction REM() {
315         return InstructionConst.DREM;
316     }
317 
NEG()318     public Instruction NEG() {
319         return InstructionConst.DNEG;
320     }
321 
LOAD(int slot)322     public Instruction LOAD(int slot) {
323         return new DLOAD(slot);
324     }
325 
STORE(int slot)326     public Instruction STORE(int slot) {
327         return new DSTORE(slot);
328     }
329 
POP()330     public Instruction POP() {
331         return POP2;
332     }
333 
CMP(boolean less)334     public Instruction CMP(boolean less) {
335         return less ? InstructionConst.DCMPG : InstructionConst.DCMPL;
336     }
337 
DUP()338     public Instruction DUP() {
339         return DUP2;
340     }
341 }
342