1// Copyright 2012 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28
29// Keep reference to original values of some global properties.  This
30// has the added benefit that the code in this file is isolated from
31// changes to these properties.
32var $floor = MathFloor;
33var $random = MathRandom;
34var $abs = MathAbs;
35
36// Instance class name can only be set on functions. That is the only
37// purpose for MathConstructor.
38function MathConstructor() {}
39%FunctionSetInstanceClassName(MathConstructor, 'Math');
40var $Math = new MathConstructor();
41$Math.__proto__ = $Object.prototype;
42%SetProperty(global, "Math", $Math, DONT_ENUM);
43
44// ECMA 262 - 15.8.2.1
45function MathAbs(x) {
46  if (%_IsSmi(x)) return x >= 0 ? x : -x;
47  if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
48  if (x === 0) return 0;  // To handle -0.
49  return x > 0 ? x : -x;
50}
51
52// ECMA 262 - 15.8.2.2
53function MathAcos(x) {
54  if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
55  return %Math_acos(x);
56}
57
58// ECMA 262 - 15.8.2.3
59function MathAsin(x) {
60  if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
61  return %Math_asin(x);
62}
63
64// ECMA 262 - 15.8.2.4
65function MathAtan(x) {
66  if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
67  return %Math_atan(x);
68}
69
70// ECMA 262 - 15.8.2.5
71// The naming of y and x matches the spec, as does the order in which
72// ToNumber (valueOf) is called.
73function MathAtan2(y, x) {
74  if (!IS_NUMBER(y)) y = NonNumberToNumber(y);
75  if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
76  return %Math_atan2(y, x);
77}
78
79// ECMA 262 - 15.8.2.6
80function MathCeil(x) {
81  if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
82  return %Math_ceil(x);
83}
84
85// ECMA 262 - 15.8.2.7
86function MathCos(x) {
87  if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
88  return %_MathCos(x);
89}
90
91// ECMA 262 - 15.8.2.8
92function MathExp(x) {
93  if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
94  return %Math_exp(x);
95}
96
97// ECMA 262 - 15.8.2.9
98function MathFloor(x) {
99  if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
100  // It's more common to call this with a positive number that's out
101  // of range than negative numbers; check the upper bound first.
102  if (x < 0x80000000 && x > 0) {
103    // Numbers in the range [0, 2^31) can be floored by converting
104    // them to an unsigned 32-bit value using the shift operator.
105    // We avoid doing so for -0, because the result of Math.floor(-0)
106    // has to be -0, which wouldn't be the case with the shift.
107    return TO_UINT32(x);
108  } else {
109    return %Math_floor(x);
110  }
111}
112
113// ECMA 262 - 15.8.2.10
114function MathLog(x) {
115  if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
116  return %_MathLog(x);
117}
118
119// ECMA 262 - 15.8.2.11
120function MathMax(arg1, arg2) {  // length == 2
121  var length = %_ArgumentsLength();
122  if (length == 2) {
123    if (!IS_NUMBER(arg1)) arg1 = NonNumberToNumber(arg1);
124    if (!IS_NUMBER(arg2)) arg2 = NonNumberToNumber(arg2);
125    if (arg2 > arg1) return arg2;
126    if (arg1 > arg2) return arg1;
127    if (arg1 == arg2) {
128      // Make sure -0 is considered less than +0.  -0 is never a Smi, +0 can be
129      // a Smi or a heap number.
130      return (arg1 == 0 && !%_IsSmi(arg1) && 1 / arg1 < 0) ? arg2 : arg1;
131    }
132    // All comparisons failed, one of the arguments must be NaN.
133    return 0/0;  // Compiler constant-folds this to NaN.
134  }
135  if (length == 0) {
136    return -1/0;  // Compiler constant-folds this to -Infinity.
137  }
138  var r = arg1;
139  if (!IS_NUMBER(r)) r = NonNumberToNumber(r);
140  if (NUMBER_IS_NAN(r)) return r;
141  for (var i = 1; i < length; i++) {
142    var n = %_Arguments(i);
143    if (!IS_NUMBER(n)) n = NonNumberToNumber(n);
144    if (NUMBER_IS_NAN(n)) return n;
145    // Make sure +0 is considered greater than -0.  -0 is never a Smi, +0 can be
146    // a Smi or heap number.
147    if (n > r || (r == 0 && n == 0 && !%_IsSmi(r) && 1 / r < 0)) r = n;
148  }
149  return r;
150}
151
152// ECMA 262 - 15.8.2.12
153function MathMin(arg1, arg2) {  // length == 2
154  var length = %_ArgumentsLength();
155  if (length == 2) {
156    if (!IS_NUMBER(arg1)) arg1 = NonNumberToNumber(arg1);
157    if (!IS_NUMBER(arg2)) arg2 = NonNumberToNumber(arg2);
158    if (arg2 > arg1) return arg1;
159    if (arg1 > arg2) return arg2;
160    if (arg1 == arg2) {
161      // Make sure -0 is considered less than +0.  -0 is never a Smi, +0 can be
162      // a Smi or a heap number.
163      return (arg1 == 0 && !%_IsSmi(arg1) && 1 / arg1 < 0) ? arg1 : arg2;
164    }
165    // All comparisons failed, one of the arguments must be NaN.
166    return 0/0;  // Compiler constant-folds this to NaN.
167  }
168  if (length == 0) {
169    return 1/0;  // Compiler constant-folds this to Infinity.
170  }
171  var r = arg1;
172  if (!IS_NUMBER(r)) r = NonNumberToNumber(r);
173  if (NUMBER_IS_NAN(r)) return r;
174  for (var i = 1; i < length; i++) {
175    var n = %_Arguments(i);
176    if (!IS_NUMBER(n)) n = NonNumberToNumber(n);
177    if (NUMBER_IS_NAN(n)) return n;
178    // Make sure -0 is considered less than +0.  -0 is never a Smi, +0 can be a
179    // Smi or a heap number.
180    if (n < r || (r == 0 && n == 0 && !%_IsSmi(n) && 1 / n < 0)) r = n;
181  }
182  return r;
183}
184
185// ECMA 262 - 15.8.2.13
186function MathPow(x, y) {
187  if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
188  if (!IS_NUMBER(y)) y = NonNumberToNumber(y);
189  return %_MathPow(x, y);
190}
191
192// ECMA 262 - 15.8.2.14
193function MathRandom() {
194  return %_RandomHeapNumber();
195}
196
197// ECMA 262 - 15.8.2.15
198function MathRound(x) {
199  if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
200  return %RoundNumber(x);
201}
202
203// ECMA 262 - 15.8.2.16
204function MathSin(x) {
205  if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
206  return %_MathSin(x);
207}
208
209// ECMA 262 - 15.8.2.17
210function MathSqrt(x) {
211  if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
212  return %_MathSqrt(x);
213}
214
215// ECMA 262 - 15.8.2.18
216function MathTan(x) {
217  if (!IS_NUMBER(x)) x = NonNumberToNumber(x);
218  return %_MathTan(x);
219}
220
221
222// -------------------------------------------------------------------
223
224function SetUpMath() {
225  %CheckIsBootstrapping();
226  // Set up math constants.
227  // ECMA-262, section 15.8.1.1.
228  %OptimizeObjectForAddingMultipleProperties($Math, 8);
229  %SetProperty($Math,
230               "E",
231               2.7182818284590452354,
232               DONT_ENUM |  DONT_DELETE | READ_ONLY);
233  // ECMA-262, section 15.8.1.2.
234  %SetProperty($Math,
235               "LN10",
236               2.302585092994046,
237               DONT_ENUM |  DONT_DELETE | READ_ONLY);
238  // ECMA-262, section 15.8.1.3.
239  %SetProperty($Math,
240               "LN2",
241               0.6931471805599453,
242               DONT_ENUM |  DONT_DELETE | READ_ONLY);
243  // ECMA-262, section 15.8.1.4.
244  %SetProperty($Math,
245               "LOG2E",
246               1.4426950408889634,
247               DONT_ENUM |  DONT_DELETE | READ_ONLY);
248  %SetProperty($Math,
249               "LOG10E",
250               0.4342944819032518,
251               DONT_ENUM |  DONT_DELETE | READ_ONLY);
252  %SetProperty($Math,
253               "PI",
254               3.1415926535897932,
255               DONT_ENUM |  DONT_DELETE | READ_ONLY);
256  %SetProperty($Math,
257               "SQRT1_2",
258               0.7071067811865476,
259               DONT_ENUM |  DONT_DELETE | READ_ONLY);
260  %SetProperty($Math,
261               "SQRT2",
262               1.4142135623730951,
263               DONT_ENUM |  DONT_DELETE | READ_ONLY);
264  %ToFastProperties($Math);
265
266  // Set up non-enumerable functions of the Math object and
267  // set their names.
268  InstallFunctions($Math, DONT_ENUM, $Array(
269    "random", MathRandom,
270    "abs", MathAbs,
271    "acos", MathAcos,
272    "asin", MathAsin,
273    "atan", MathAtan,
274    "ceil", MathCeil,
275    "cos", MathCos,
276    "exp", MathExp,
277    "floor", MathFloor,
278    "log", MathLog,
279    "round", MathRound,
280    "sin", MathSin,
281    "sqrt", MathSqrt,
282    "tan", MathTan,
283    "atan2", MathAtan2,
284    "pow", MathPow,
285    "max", MathMax,
286    "min", MathMin
287  ));
288}
289
290SetUpMath();
291