Source code drop for the Actionscript virtual machine in the Adobe Flash Player for December 2013
199 lines
6.5 KiB
C++
199 lines
6.5 KiB
C++
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
|
|
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
#include "avmplus.h"
|
|
#include "BuiltinNatives.h"
|
|
|
|
namespace avmplus
|
|
{
|
|
NumberClass::NumberClass(VTable* cvtable)
|
|
: ClassClosure(cvtable)
|
|
{
|
|
toplevel()->_numberClass = this;
|
|
|
|
// prototype objects are always vanilla objects.
|
|
createVanillaPrototype();
|
|
}
|
|
|
|
Atom NumberClass::construct(int argc, Atom* argv)
|
|
{
|
|
// Number called as constructor creates new Number instance
|
|
// Note: SpiderMonkey returns 0 for new Number() with no args
|
|
if (argc == 0)
|
|
return zeroIntAtom; // yep this is zero atom
|
|
else
|
|
return core()->numberAtom(argv[1]);
|
|
// TODO ArgumentError if argc > 1
|
|
}
|
|
|
|
Stringp NumberClass::_convert(double n, int precision, int mode)
|
|
{
|
|
AvmCore* core = this->core();
|
|
|
|
if (mode == MathUtils::DTOSTR_PRECISION)
|
|
{
|
|
if (precision < 1 || precision > 21) {
|
|
toplevel()->throwRangeError(kInvalidPrecisionError, core->toErrorString(precision), core->toErrorString(1), core->toErrorString(21));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (precision < 0 || precision > 20) {
|
|
toplevel()->throwRangeError(kInvalidPrecisionError, core->toErrorString(precision), core->toErrorString(0), core->toErrorString(20));
|
|
}
|
|
}
|
|
|
|
return MathUtils::convertDoubleToString(core, n, mode, precision);
|
|
}
|
|
|
|
Stringp NumberClass::_numberToString(double dVal, int radix)
|
|
{
|
|
AvmCore* core = this->core();
|
|
|
|
if (radix == 10 || MathUtils::isInfinite(dVal) || MathUtils::isNaN(dVal))
|
|
return core->doubleToString(dVal);
|
|
|
|
if (radix < 2 || radix > 36)
|
|
toplevel()->throwRangeError(kInvalidRadixError, core->toErrorString(radix));
|
|
|
|
// convertDoubleToStringRadix will convert the integer part of dVal
|
|
// to a string in the specified radix, and it will handle large numbers
|
|
// beyond the range of int/uint. It will not handle the fractional
|
|
// part. To properly handle that, MathUtils::convertDoubleToString
|
|
// would have to handle any base. That's a lot of extra code and complexity for
|
|
// something the ES3 spec says is implementation dependent
|
|
// (i.e. we're not required to do it)
|
|
|
|
return MathUtils::convertDoubleToStringRadix(core, dVal, radix);
|
|
}
|
|
|
|
// volatile externals to keep the constant propagator from outsmarting us.
|
|
volatile double minDouble = 4.94e-324;
|
|
volatile double minNormalizedDouble = 2.2250738585072014e-308; // really needs all these digits to get it right
|
|
|
|
double NumberClass::_minValue()
|
|
{
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=555805
|
|
//
|
|
// The ARM architecture saves transistors by not implementing subnormal floating point numbers in
|
|
// hardware. Instead, those values produce a trap ("bounce") so that they can be emulated in software.
|
|
// There is, however, a "RunFast" mode that suppresses the "bounce" and instead does a
|
|
// "flush-to-zero" on underflow. Some platforms operate in RunFast mode by default and while it
|
|
// is possible for user code to turn off that mode, it seems to be in the OS's purview to install
|
|
// the trap handler. Long story short, on certain ARM-based platforms, values smaller than the smallest
|
|
// normalized floating point value are snapped (flushed) to zero.
|
|
//
|
|
// The definitive reference URLs appear to be perishable, but the terms in quotes above are useful in searches:
|
|
// http://www.google.com/search?q=ARM+runfast+flush-to-zero+bounce
|
|
//
|
|
// The issue seems specific to ARM processors (though perhaps other mobilized cores as well), but will only occur
|
|
// if the platform opts not to install an emulator trap. So we dynamically find the smallest value, being wary of
|
|
// techniques that might be optimized away by compilers (and especially cross-compilers!).
|
|
|
|
double minValue = minDouble;
|
|
if (minValue == 0.0)
|
|
minValue = minNormalizedDouble;
|
|
#ifdef _DEBUG
|
|
// It's going to be either 0x1 (~4.94e-324) if subnormals are supported or 0x0010000000000000 (~2.225e-308) if not.
|
|
double_overlay d(minValue);
|
|
AvmAssert((d.words.msw == 0 && d.words.lsw == 1) || (d.words.msw == 0x00100000 && d.words.lsw == 0));
|
|
#endif
|
|
return minValue;
|
|
}
|
|
|
|
double NumberClass::abs(double x)
|
|
{
|
|
return MathUtils::abs(x);
|
|
}
|
|
|
|
double NumberClass::acos(double x)
|
|
{
|
|
return MathUtils::acos(x);
|
|
}
|
|
|
|
double NumberClass::asin(double x)
|
|
{
|
|
return MathUtils::asin(x);
|
|
}
|
|
|
|
double NumberClass::atan(double x)
|
|
{
|
|
return MathUtils::atan(x);
|
|
}
|
|
|
|
double NumberClass::atan2(double y, double x)
|
|
{
|
|
return MathUtils::atan2(y, x);
|
|
}
|
|
|
|
double NumberClass::ceil(double x)
|
|
{
|
|
return MathUtils::ceil(x);
|
|
}
|
|
|
|
double NumberClass::cos(double x)
|
|
{
|
|
return MathUtils::cos(x);
|
|
}
|
|
|
|
double NumberClass::exp(double x)
|
|
{
|
|
return MathUtils::exp(x);
|
|
}
|
|
|
|
double NumberClass::floor(double x)
|
|
{
|
|
return MathUtils::floor(x);
|
|
}
|
|
|
|
double NumberClass::log(double x)
|
|
{
|
|
return MathUtils::log(x);
|
|
}
|
|
|
|
double NumberClass::pow(double x, double y)
|
|
{
|
|
return MathUtils::pow(x, y);
|
|
}
|
|
|
|
double NumberClass::random()
|
|
{
|
|
// Share the RNG stream between Math and Number.
|
|
return toplevel()->builtinClasses()->get_MathClass()->random();
|
|
}
|
|
|
|
double NumberClass::round(double x)
|
|
{
|
|
return MathUtils::round(x);
|
|
}
|
|
|
|
double NumberClass::sin(double x)
|
|
{
|
|
return MathUtils::sin(x);
|
|
}
|
|
|
|
double NumberClass::sqrt(double x)
|
|
{
|
|
return MathUtils::sqrt(x);
|
|
}
|
|
|
|
double NumberClass::tan(double x)
|
|
{
|
|
return MathUtils::tan(x);
|
|
}
|
|
|
|
double NumberClass::min(double x, double y, const Atom* argv, uint32_t argc)
|
|
{
|
|
return MathClass::minImpl(x,y,argv,argc);
|
|
}
|
|
|
|
double NumberClass::max(double x, double y, const Atom* argv, uint32_t argc)
|
|
{
|
|
return MathClass::maxImpl(x,y,argv,argc);
|
|
}
|
|
}
|