Ignore:
Timestamp:
Jun 28, 2008, 2:22:01 PM (17 years ago)
Author:
[email protected]
Message:

JavaScriptCore:

2008-06-28 Sam Weinig <[email protected]>

Rubber-stamped by Oliver Hunt.

Splits FunctionConstructor out of FunctionPrototype.h/cpp
Splits NumberConstructor and NumberPrototype out of NumberObject.h/cpp
Rename object_object.h/cpp to ObjectPrototype.h/cpp and split out ObjectConstructor.

  • API/JSCallbackConstructor.cpp:
  • API/JSClassRef.cpp:
  • API/JSObjectRef.cpp:
  • DerivedSources.make:
  • GNUmakefile.am:
  • JavaScriptCore.pri:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • JavaScriptCoreSources.bkl:
  • VM/Machine.cpp:
  • kjs/AllInOneFile.cpp:
  • kjs/ArrayConstructor.cpp:
  • kjs/ArrayConstructor.h:
  • kjs/FunctionConstructor.cpp: Copied from JavaScriptCore/kjs/FunctionPrototype.cpp.
  • kjs/FunctionConstructor.h: Copied from JavaScriptCore/kjs/FunctionPrototype.h.
  • kjs/FunctionPrototype.cpp:
  • kjs/FunctionPrototype.h:
  • kjs/JSFunction.cpp:
  • kjs/JSGlobalObject.cpp:
  • kjs/JSImmediate.cpp:
  • kjs/MathObject.h:
  • kjs/NumberConstructor.cpp: Copied from JavaScriptCore/kjs/NumberObject.cpp.
  • kjs/NumberConstructor.h: Copied from JavaScriptCore/kjs/NumberObject.h.
  • kjs/NumberObject.cpp:
  • kjs/NumberObject.h:
  • kjs/NumberPrototype.cpp: Copied from JavaScriptCore/kjs/NumberObject.cpp.
  • kjs/NumberPrototype.h: Copied from JavaScriptCore/kjs/NumberObject.h.
  • kjs/ObjectConstructor.cpp: Copied from JavaScriptCore/kjs/object_object.cpp.
  • kjs/ObjectConstructor.h: Copied from JavaScriptCore/kjs/object_object.h.
  • kjs/ObjectPrototype.cpp: Copied from JavaScriptCore/kjs/object_object.cpp.
  • kjs/ObjectPrototype.h: Copied from JavaScriptCore/kjs/object_object.h.
  • kjs/RegExpObject.h:
  • kjs/Shell.cpp:
  • kjs/error_object.h:
  • kjs/internal.cpp:
  • kjs/nodes.cpp:
  • kjs/object_object.cpp: Removed.
  • kjs/object_object.h: Removed.
  • kjs/string_object.h:

WebCore:

2008-06-28 Sam Weinig <[email protected]>

Rubber-stamped by Oliver Hunt.

Update includes after remaming object_object.h to ObjectPrototype.h and
splitting FunctionConstructor out of FunctionPrototype.h

  • ForwardingHeaders/kjs/FunctionConstructor.h: Added.
  • ForwardingHeaders/kjs/ObjectPrototype.h: Copied from WebCore/ForwardingHeaders/kjs/object_object.h.
  • ForwardingHeaders/kjs/object_object.h: Removed.
  • bindings/js/JSEventListener.cpp:
  • bindings/scripts/CodeGeneratorJS.pm:
  • bridge/qt/qt_instance.cpp:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/kjs/NumberObject.cpp

    r34821 r34854  
    2222#include "config.h"
    2323#include "NumberObject.h"
    24 #include "NumberObject.lut.h"
    25 
    26 #include "dtoa.h"
    27 #include "error_object.h"
    28 #include "operations.h"
    29 #include <wtf/Assertions.h>
    30 #include <wtf/MathExtras.h>
    31 #include <wtf/Vector.h>
    3224
    3325namespace KJS {
    34 
    35 // ------------------------------ NumberObject ----------------------------
    3626
    3727const ClassInfo NumberObject::info = { "Number", 0, 0, 0 };
     
    4737}
    4838
    49 // ------------------------------ NumberPrototype ---------------------------
    50 
    51 static JSValue* numberProtoFuncToString(ExecState*, JSObject*, JSValue*, const ArgList&);
    52 static JSValue* numberProtoFuncToLocaleString(ExecState*, JSObject*, JSValue*, const ArgList&);
    53 static JSValue* numberProtoFuncValueOf(ExecState*, JSObject*, JSValue*, const ArgList&);
    54 static JSValue* numberProtoFuncToFixed(ExecState*, JSObject*, JSValue*, const ArgList&);
    55 static JSValue* numberProtoFuncToExponential(ExecState*, JSObject*, JSValue*, const ArgList&);
    56 static JSValue* numberProtoFuncToPrecision(ExecState*, JSObject*, JSValue*, const ArgList&);
    57 
    58 // ECMA 15.7.4
    59 
    60 NumberPrototype::NumberPrototype(ExecState* exec, ObjectPrototype* objectPrototype, FunctionPrototype* functionPrototype)
    61     : NumberObject(objectPrototype)
    62 {
    63     setInternalValue(jsNumber(exec, 0));
    64 
    65     // The constructor will be added later, after NumberConstructor has been constructed
    66 
    67     putDirectFunction(new (exec) PrototypeFunction(exec, functionPrototype, 1, exec->propertyNames().toString, numberProtoFuncToString), DontEnum);
    68     putDirectFunction(new (exec) PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().toLocaleString, numberProtoFuncToLocaleString), DontEnum);
    69     putDirectFunction(new (exec) PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().valueOf, numberProtoFuncValueOf), DontEnum);
    70     putDirectFunction(new (exec) PrototypeFunction(exec, functionPrototype, 1, exec->propertyNames().toFixed, numberProtoFuncToFixed), DontEnum);
    71     putDirectFunction(new (exec) PrototypeFunction(exec, functionPrototype, 1, exec->propertyNames().toExponential, numberProtoFuncToExponential), DontEnum);
    72     putDirectFunction(new (exec) PrototypeFunction(exec, functionPrototype, 1, exec->propertyNames().toPrecision, numberProtoFuncToPrecision), DontEnum);
    73 }
    74 
    75 // ------------------------------ Functions ---------------------------
    76 
    77 // ECMA 15.7.4.2 - 15.7.4.7
    78 
    79 static UString integer_part_noexp(double d)
    80 {
    81     int decimalPoint;
    82     int sign;
    83     char* result = dtoa(d, 0, &decimalPoint, &sign, NULL);
    84     bool resultIsInfOrNan = (decimalPoint == 9999);
    85     size_t length = strlen(result);
    86 
    87     UString str = sign ? "-" : "";
    88     if (resultIsInfOrNan)
    89         str += result;
    90     else if (decimalPoint <= 0)
    91         str += "0";
    92     else {
    93         Vector<char, 1024> buf(decimalPoint + 1);
    94 
    95         if (static_cast<int>(length) <= decimalPoint) {
    96             strcpy(buf.data(), result);
    97             memset(buf.data() + length, '0', decimalPoint - length);
    98         } else
    99             strncpy(buf.data(), result, decimalPoint);
    100 
    101         buf[decimalPoint] = '\0';
    102         str.append(buf.data());
    103     }
    104 
    105     freedtoa(result);
    106 
    107     return str;
    108 }
    109 
    110 static UString char_sequence(char c, int count)
    111 {
    112     Vector<char, 2048> buf(count + 1, c);
    113     buf[count] = '\0';
    114 
    115     return UString(buf.data());
    116 }
    117 
    118 static double intPow10(int e)
    119 {
    120     // This function uses the "exponentiation by squaring" algorithm and
    121     // long double to quickly and precisely calculate integer powers of 10.0.
    122 
    123     // This is a handy workaround for <rdar://problem/4494756>
    124 
    125     if (e == 0)
    126         return 1.0;
    127 
    128     bool negative = e < 0;
    129     unsigned exp = negative ? -e : e;
    130 
    131     long double result = 10.0;
    132     bool foundOne = false;
    133     for (int bit = 31; bit >= 0; bit--) {
    134         if (!foundOne) {
    135             if ((exp >> bit) & 1)
    136                 foundOne = true;
    137         } else {
    138             result = result * result;
    139             if ((exp >> bit) & 1)
    140                 result = result * 10.0;
    141         }
    142     }
    143 
    144     if (negative)
    145         return static_cast<double>(1.0 / result);
    146     return static_cast<double>(result);
    147 }
    148 
    149 
    150 JSValue* numberProtoFuncToString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    151 {
    152     JSValue* v = thisValue->getJSNumber();
    153     if (!v)
    154         return throwError(exec, TypeError);
    155 
    156     double radixAsDouble = args[0]->toInteger(exec); // nan -> 0
    157     if (radixAsDouble == 10 || args[0]->isUndefined())
    158         return jsString(exec, v->toString(exec));
    159 
    160     if (radixAsDouble < 2 || radixAsDouble > 36)
    161         return throwError(exec, RangeError, "toString() radix argument must be between 2 and 36");
    162 
    163     int radix = static_cast<int>(radixAsDouble);
    164     const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
    165     // INT_MAX results in 1024 characters left of the dot with radix 2
    166     // give the same space on the right side. safety checks are in place
    167     // unless someone finds a precise rule.
    168     char s[2048 + 3];
    169     const char* lastCharInString = s + sizeof(s) - 1;
    170     double x = v->uncheckedGetNumber();
    171     if (isnan(x) || isinf(x))
    172         return jsString(exec, UString::from(x));
    173 
    174     bool isNegative = x < 0.0;
    175     if (isNegative)
    176         x = -x;
    177 
    178     double integerPart = floor(x);
    179     char* decimalPoint = s + sizeof(s) / 2;
    180 
    181     // convert integer portion
    182     char* p = decimalPoint;
    183     double d = integerPart;
    184     do {
    185         int remainderDigit = static_cast<int>(fmod(d, radix));
    186         *--p = digits[remainderDigit];
    187         d /= radix;
    188     } while ((d <= -1.0 || d >= 1.0) && s < p);
    189 
    190     if (isNegative)
    191         *--p = '-';
    192     char* startOfResultString = p;
    193     ASSERT(s <= startOfResultString);
    194 
    195     d = x - integerPart;
    196     p = decimalPoint;
    197     const double epsilon = 0.001; // TODO: guessed. base on radix ?
    198     bool hasFractionalPart = (d < -epsilon || d > epsilon);
    199     if (hasFractionalPart) {
    200         *p++ = '.';
    201         do {
    202             d *= radix;
    203             const int digit = static_cast<int>(d);
    204             *p++ = digits[digit];
    205             d -= digit;
    206         } while ((d < -epsilon || d > epsilon) && p < lastCharInString);
    207     }
    208     *p = '\0';
    209     ASSERT(p < s + sizeof(s));
    210 
    211     return jsString(exec, startOfResultString);
    212 }
    213 
    214 JSValue* numberProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    215 {
    216     // FIXME: Not implemented yet.
    217 
    218     JSValue* v = thisValue->getJSNumber();
    219     if (!v)
    220         return throwError(exec, TypeError);
    221 
    222     return jsString(exec, v->toString(exec));
    223 }
    224 
    225 JSValue* numberProtoFuncValueOf(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    226 {
    227     JSValue* v = thisValue->getJSNumber();
    228     if (!v)
    229         return throwError(exec, TypeError);
    230 
    231     return v;
    232 }
    233 
    234 JSValue* numberProtoFuncToFixed(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    235 {
    236     JSValue* v = thisValue->getJSNumber();
    237     if (!v)
    238         return throwError(exec, TypeError);
    239 
    240     JSValue* fractionDigits = args[0];
    241     double df = fractionDigits->toInteger(exec);
    242     if (!(df >= 0 && df <= 20))
    243         return throwError(exec, RangeError, "toFixed() digits argument must be between 0 and 20");
    244     int f = (int)df;
    245 
    246     double x = v->uncheckedGetNumber();
    247     if (isnan(x))
    248         return jsString(exec, "NaN");
    249 
    250     UString s;
    251     if (x < 0) {
    252         s.append('-');
    253         x = -x;
    254     } else if (x == -0.0)
    255         x = 0;
    256 
    257     if (x >= pow(10.0, 21.0))
    258         return jsString(exec, s + UString::from(x));
    259 
    260     const double tenToTheF = pow(10.0, f);
    261     double n = floor(x * tenToTheF);
    262     if (fabs(n / tenToTheF - x) >= fabs((n + 1) / tenToTheF - x))
    263         n++;
    264 
    265     UString m = integer_part_noexp(n);
    266 
    267     int k = m.size();
    268     if (k <= f) {
    269         UString z;
    270         for (int i = 0; i < f + 1 - k; i++)
    271             z.append('0');
    272         m = z + m;
    273         k = f + 1;
    274         ASSERT(k == m.size());
    275     }
    276     int kMinusf = k - f;
    277     if (kMinusf < m.size())
    278         return jsString(exec, s + m.substr(0, kMinusf) + "." + m.substr(kMinusf));
    279     return jsString(exec, s + m.substr(0, kMinusf));
    280 }
    281 
    282 static void fractionalPartToString(char* buf, int& i, const char* result, int resultLength, int fractionalDigits)
    283 {
    284     if (fractionalDigits <= 0)
    285         return;
    286 
    287     int fDigitsInResult = static_cast<int>(resultLength) - 1;
    288     buf[i++] = '.';
    289     if (fDigitsInResult > 0) {
    290         if (fractionalDigits < fDigitsInResult) {
    291             strncpy(buf + i, result + 1, fractionalDigits);
    292             i += fractionalDigits;
    293         } else {
    294             strcpy(buf + i, result + 1);
    295             i += static_cast<int>(resultLength) - 1;
    296         }
    297     }
    298 
    299     for (int j = 0; j < fractionalDigits - fDigitsInResult; j++)
    300         buf[i++] = '0';
    301 }
    302 
    303 static void exponentialPartToString(char* buf, int& i, int decimalPoint)
    304 {
    305     buf[i++] = 'e';
    306     buf[i++] = (decimalPoint >= 0) ? '+' : '-';
    307     // decimalPoint can't be more than 3 digits decimal given the
    308     // nature of float representation
    309     int exponential = decimalPoint - 1;
    310     if (exponential < 0)
    311         exponential *= -1;
    312     if (exponential >= 100)
    313         buf[i++] = static_cast<char>('0' + exponential / 100);
    314     if (exponential >= 10)
    315         buf[i++] = static_cast<char>('0' + (exponential % 100) / 10);
    316     buf[i++] = static_cast<char>('0' + exponential % 10);
    317 }
    318 
    319 JSValue* numberProtoFuncToExponential(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    320 {
    321     JSValue* v = thisValue->getJSNumber();
    322     if (!v)
    323         return throwError(exec, TypeError);
    324 
    325     double x = v->uncheckedGetNumber();
    326 
    327     if (isnan(x) || isinf(x))
    328         return jsString(exec, UString::from(x));
    329 
    330     JSValue* fractionalDigitsValue = args[0];
    331     double df = fractionalDigitsValue->toInteger(exec);
    332     if (!(df >= 0 && df <= 20))
    333         return throwError(exec, RangeError, "toExponential() argument must between 0 and 20");
    334     int fractionalDigits = (int)df;
    335     bool includeAllDigits = fractionalDigitsValue->isUndefined();
    336 
    337     int decimalAdjust = 0;
    338     if (x && !includeAllDigits) {
    339         double logx = floor(log10(fabs(x)));
    340         x /= pow(10.0, logx);
    341         const double tenToTheF = pow(10.0, fractionalDigits);
    342         double fx = floor(x * tenToTheF) / tenToTheF;
    343         double cx = ceil(x * tenToTheF) / tenToTheF;
    344 
    345         if (fabs(fx - x) < fabs(cx - x))
    346             x = fx;
    347         else
    348             x = cx;
    349 
    350         decimalAdjust = static_cast<int>(logx);
    351     }
    352 
    353     if (isnan(x))
    354         return jsString(exec, "NaN");
    355 
    356     if (x == -0.0) // (-0.0).toExponential() should print as 0 instead of -0
    357         x = 0;
    358 
    359     int decimalPoint;
    360     int sign;
    361     char* result = dtoa(x, 0, &decimalPoint, &sign, NULL);
    362     size_t resultLength = strlen(result);
    363     decimalPoint += decimalAdjust;
    364 
    365     int i = 0;
    366     char buf[80]; // digit + '.' + fractionDigits (max 20) + 'e' + sign + exponent (max?)
    367     if (sign)
    368         buf[i++] = '-';
    369 
    370     if (decimalPoint == 999) // ? 9999 is the magical "result is Inf or NaN" value.  what's 999??
    371         strcpy(buf + i, result);
    372     else {
    373         buf[i++] = result[0];
    374 
    375         if (includeAllDigits)
    376             fractionalDigits = static_cast<int>(resultLength) - 1;
    377 
    378         fractionalPartToString(buf, i, result, resultLength, fractionalDigits);
    379         exponentialPartToString(buf, i, decimalPoint);
    380         buf[i++] = '\0';
    381     }
    382     ASSERT(i <= 80);
    383 
    384     freedtoa(result);
    385 
    386     return jsString(exec, buf);
    387 }
    388 
    389 JSValue* numberProtoFuncToPrecision(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    390 {
    391     JSValue* v = thisValue->getJSNumber();
    392     if (!v)
    393         return throwError(exec, TypeError);
    394 
    395     double doublePrecision = args[0]->toIntegerPreserveNaN(exec);
    396     double x = v->uncheckedGetNumber();
    397     if (args[0]->isUndefined() || isnan(x) || isinf(x))
    398         return jsString(exec, v->toString(exec));
    399 
    400     UString s;
    401     if (x < 0) {
    402         s = "-";
    403         x = -x;
    404     }
    405 
    406     if (!(doublePrecision >= 1 && doublePrecision <= 21)) // true for NaN
    407         return throwError(exec, RangeError, "toPrecision() argument must be between 1 and 21");
    408     int precision = (int)doublePrecision;
    409 
    410     int e = 0;
    411     UString m;
    412     if (x) {
    413         e = static_cast<int>(log10(x));
    414         double tens = intPow10(e - precision + 1);
    415         double n = floor(x / tens);
    416         if (n < intPow10(precision - 1)) {
    417             e = e - 1;
    418             tens = intPow10(e - precision + 1);
    419             n = floor(x / tens);
    420         }
    421 
    422         if (fabs((n + 1.0) * tens - x) <= fabs(n * tens - x))
    423             ++n;
    424         // maintain n < 10^(precision)
    425         if (n >= intPow10(precision)) {
    426             n /= 10.0;
    427             e += 1;
    428         }
    429         ASSERT(intPow10(precision - 1) <= n);
    430         ASSERT(n < intPow10(precision));
    431 
    432         m = integer_part_noexp(n);
    433         if (e < -6 || e >= precision) {
    434             if (m.size() > 1)
    435                 m = m.substr(0, 1) + "." + m.substr(1);
    436             if (e >= 0)
    437                 return jsString(exec, s + m + "e+" + UString::from(e));
    438             return jsString(exec, s + m + "e-" + UString::from(-e));
    439         }
    440     } else {
    441         m = char_sequence('0', precision);
    442         e = 0;
    443     }
    444 
    445     if (e == precision - 1)
    446         return jsString(exec, s + m);
    447     if (e >= 0) {
    448         if (e + 1 < m.size())
    449             return jsString(exec, s + m.substr(0, e + 1) + "." + m.substr(e + 1));
    450         return jsString(exec, s + m);
    451     }
    452     return jsString(exec, s + "0." + char_sequence('0', -(e + 1)) + m);
    453 }
    454 
    455 // ------------------------------ NumberConstructor ------------------------------
    456 
    457 const ClassInfo NumberConstructor::info = { "Function", &InternalFunction::info, 0, ExecState::numberTable };
    458 
    459 /* Source for NumberObject.lut.h
    460 @begin numberTable
    461   NaN                   NumberConstructor::NaNValue       DontEnum|DontDelete|ReadOnly
    462   NEGATIVE_INFINITY     NumberConstructor::NegInfinity    DontEnum|DontDelete|ReadOnly
    463   POSITIVE_INFINITY     NumberConstructor::PosInfinity    DontEnum|DontDelete|ReadOnly
    464   MAX_VALUE             NumberConstructor::MaxValue       DontEnum|DontDelete|ReadOnly
    465   MIN_VALUE             NumberConstructor::MinValue       DontEnum|DontDelete|ReadOnly
    466 @end
    467 */
    468 NumberConstructor::NumberConstructor(ExecState* exec, FunctionPrototype* funcProto, NumberPrototype* numberProto)
    469     : InternalFunction(funcProto, Identifier(exec, numberProto->info.className))
    470 {
    471     // Number.Prototype
    472     putDirect(exec->propertyNames().prototype, numberProto, DontEnum|DontDelete|ReadOnly);
    473 
    474     // no. of arguments for constructor
    475     putDirect(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontEnum | DontDelete);
    476 }
    477 
    478 bool NumberConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
    479 {
    480     return getStaticValueSlot<NumberConstructor, InternalFunction>(exec, ExecState::numberTable(exec), this, propertyName, slot);
    481 }
    482 
    483 JSValue* NumberConstructor::getValueProperty(ExecState* exec, int token) const
    484 {
    485     // ECMA 15.7.3
    486     switch (token) {
    487         case NaNValue:
    488             return jsNaN(exec);
    489         case NegInfinity:
    490             return jsNumberCell(exec, -Inf);
    491         case PosInfinity:
    492             return jsNumberCell(exec, Inf);
    493         case MaxValue:
    494             return jsNumberCell(exec, 1.7976931348623157E+308);
    495         case MinValue:
    496             return jsNumberCell(exec, 5E-324);
    497     }
    498     ASSERT_NOT_REACHED();
    499     return jsNull();
    500 }
    501 
    502 // ECMA 15.7.1
    503 static JSObject* constructWithNumberConstructor(ExecState* exec, JSObject*, const ArgList& args)
    504 {
    505     NumberObject* obj = new (exec) NumberObject(exec->lexicalGlobalObject()->numberPrototype());
    506     double n = args.isEmpty() ? 0 : args[0]->toNumber(exec);
    507     obj->setInternalValue(jsNumber(exec, n));
    508     return obj;
    509 }
    510 
    511 ConstructType NumberConstructor::getConstructData(ConstructData& constructData)
    512 {
    513     constructData.native.function = constructWithNumberConstructor;
    514     return ConstructTypeNative;
    515 }
    516 
    517 // ECMA 15.7.2
    518 static JSValue* callNumberConstructor(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
    519 {
    520     return jsNumber(exec, args.isEmpty() ? 0 : args[0]->toNumber(exec));
    521 }
    522 
    523 CallType NumberConstructor::getCallData(CallData& callData)
    524 {
    525     callData.native.function = callNumberConstructor;
    526     return CallTypeNative;
    527 }
    528 
    529 NumberObject* constructNumber(ExecState* exec, JSNumberCell* number)
    530 {
    531     NumberObject* obj = new (exec) NumberObject(exec->lexicalGlobalObject()->numberPrototype());
    532     obj->setInternalValue(number);
    533     return obj;
    534 }
    535 
    536 NumberObject* constructNumberFromImmediateNumber(ExecState* exec, JSValue* value)
    537 {
    538     NumberObject* obj = new (exec) NumberObject(exec->lexicalGlobalObject()->numberPrototype());
    539     obj->setInternalValue(value);
    540     return obj;
    541 }
    542 
    54339} // namespace KJS
Note: See TracChangeset for help on using the changeset viewer.