Merge remote-tracking branch 'redux/master' into sh4-pool
[tamarin-stm.git] / core / NumberClass.cpp
blobe707a53294af5ce96013c168febcd7e68cbcc8cc
1 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2 /* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is [Open Source Virtual Machine.].
18 * The Initial Developer of the Original Code is
19 * Adobe System Incorporated.
20 * Portions created by the Initial Developer are Copyright (C) 2004-2006
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Adobe AS3 Team
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
41 #include "avmplus.h"
42 #include "BuiltinNatives.h"
44 namespace avmplus
46 NumberClass::NumberClass(VTable* cvtable)
47 : ClassClosure(cvtable)
49 toplevel()->_numberClass = this;
51 // prototype objects are always vanilla objects.
52 createVanillaPrototype();
55 Atom NumberClass::construct(int argc, Atom* argv)
57 // Number called as constructor creates new Number instance
58 // Note: SpiderMonkey returns 0 for new Number() with no args
59 if (argc == 0)
60 return zeroIntAtom; // yep this is zero atom
61 else
62 return core()->numberAtom(argv[1]);
63 // TODO ArgumentError if argc > 1
66 Stringp NumberClass::_convert(double n, int precision, int mode)
68 AvmCore* core = this->core();
70 if (mode == MathUtils::DTOSTR_PRECISION)
72 if (precision < 1 || precision > 21) {
73 toplevel()->throwRangeError(kInvalidPrecisionError, core->toErrorString(precision), core->toErrorString(1), core->toErrorString(21));
76 else
78 if (precision < 0 || precision > 20) {
79 toplevel()->throwRangeError(kInvalidPrecisionError, core->toErrorString(precision), core->toErrorString(0), core->toErrorString(20));
83 return MathUtils::convertDoubleToString(core, n, mode, precision);
86 Stringp NumberClass::_numberToString(double dVal, int radix)
88 AvmCore* core = this->core();
90 if (radix == 10 || MathUtils::isInfinite(dVal) || MathUtils::isNaN(dVal))
91 return core->doubleToString(dVal);
93 if (radix < 2 || radix > 36)
94 toplevel()->throwRangeError(kInvalidRadixError, core->toErrorString(radix));
96 // convertDoubleToStringRadix will convert the integer part of dVal
97 // to a string in the specified radix, and it will handle large numbers
98 // beyond the range of int/uint. It will not handle the fractional
99 // part. To properly handle that, MathUtils::convertDoubleToString
100 // would have to handle any base. That's a lot of extra code and complexity for
101 // something the ES3 spec says is implementation dependent
102 // (i.e. we're not required to do it)
104 return MathUtils::convertDoubleToStringRadix(core, dVal, radix);
107 // volatile externals to keep the constant propagator from outsmarting us.
108 volatile double minDouble = 4.94e-324;
109 volatile double minNormalizedDouble = 2.2250738585072014e-308; // really needs all these digits to get it right
111 double NumberClass::_minValue()
113 // https://bugzilla.mozilla.org/show_bug.cgi?id=555805
115 // The ARM architecture saves transistors by not implementing subnormal floating point numbers in
116 // hardware. Instead, those values produce a trap ("bounce") so that they can be emulated in software.
117 // There is, however, a "RunFast" mode that suppresses the "bounce" and instead does a
118 // "flush-to-zero" on underflow. Some platforms operate in RunFast mode by default and while it
119 // is possible for user code to turn off that mode, it seems to be in the OS's purview to install
120 // the trap handler. Long story short, on certain ARM-based platforms, values smaller than the smallest
121 // normalized floating point value are snapped (flushed) to zero.
123 // The definitive reference URLs appear to be perishable, but the terms in quotes above are useful in searches:
124 // http://www.google.com/search?q=ARM+runfast+flush-to-zero+bounce
126 // The issue seems specific to ARM processors (though perhaps other mobilized cores as well), but will only occur
127 // if the platform opts not to install an emulator trap. So we dynamically find the smallest value, being wary of
128 // techniques that might be optimized away by compilers (and especially cross-compilers!).
130 double minValue = minDouble;
131 if (minValue == 0.0)
132 minValue = minNormalizedDouble;
133 #ifdef _DEBUG
134 // It's going to be either 0x1 (~4.94e-324) if subnormals are supported or 0x0010000000000000 (~2.225e-308) if not.
135 double_overlay d(minValue);
136 AvmAssert((d.words.msw == 0 && d.words.lsw == 1) || (d.words.msw == 0x00100000 && d.words.lsw == 0));
137 #endif
138 return minValue;