Ignore:
Timestamp:
Nov 8, 2007, 12:31:26 PM (18 years ago)
Author:
[email protected]
Message:

JavaScriptCore:

Reviewed by Darin.

Convert JavaScript internal function objects to use one class per
function. This avoids a switch statement inside what used to be
the shared function classes and will allow Shark to better analyze
the code.

To make this switch, the value property of the HashEntry was changed
to a union of an intptr_t (which is used to continue handle valueGetters)
and function pointer which points to a static constructor for the
individual new function objects.

SunSpider claims this is a 0.5% speedup.

  • kjs/array_object.cpp: (KJS::ArrayPrototype::getOwnPropertySlot): (KJS::getProperty): (KJS::ArrayProtoFuncToString::callAsFunction): (KJS::ArrayProtoFuncToLocaleString::callAsFunction): (KJS::ArrayProtoFuncJoin::callAsFunction): (KJS::ArrayProtoFuncConcat::callAsFunction): (KJS::ArrayProtoFuncPop::callAsFunction): (KJS::ArrayProtoFuncPush::callAsFunction): (KJS::ArrayProtoFuncReverse::callAsFunction): (KJS::ArrayProtoFuncShift::callAsFunction): (KJS::ArrayProtoFuncSlice::callAsFunction): (KJS::ArrayProtoFuncSort::callAsFunction): (KJS::ArrayProtoFuncSplice::callAsFunction): (KJS::ArrayProtoFuncUnShift::callAsFunction): (KJS::ArrayProtoFuncFilter::callAsFunction): (KJS::ArrayProtoFuncMap::callAsFunction): (KJS::ArrayProtoFuncEvery::callAsFunction): (KJS::ArrayProtoFuncForEach::callAsFunction): (KJS::ArrayProtoFuncSome::callAsFunction): (KJS::ArrayProtoFuncIndexOf::callAsFunction): (KJS::ArrayProtoFuncLastIndexOf::callAsFunction):
  • kjs/array_object.h: (KJS::ArrayPrototype::classInfo):
  • kjs/create_hash_table:
  • kjs/date_object.cpp: (KJS::DatePrototype::getOwnPropertySlot): (KJS::DateProtoFuncToString::callAsFunction): (KJS::DateProtoFuncToUTCString::callAsFunction): (KJS::DateProtoFuncToDateString::callAsFunction): (KJS::DateProtoFuncToTimeString::callAsFunction): (KJS::DateProtoFuncToLocaleString::callAsFunction): (KJS::DateProtoFuncToLocaleDateString::callAsFunction): (KJS::DateProtoFuncToLocaleTimeString::callAsFunction): (KJS::DateProtoFuncValueOf::callAsFunction): (KJS::DateProtoFuncGetTime::callAsFunction): (KJS::DateProtoFuncGetFullYear::callAsFunction): (KJS::DateProtoFuncGetUTCFullYear::callAsFunction): (KJS::DateProtoFuncToGMTString::callAsFunction): (KJS::DateProtoFuncGetMonth::callAsFunction): (KJS::DateProtoFuncGetUTCMonth::callAsFunction): (KJS::DateProtoFuncGetDate::callAsFunction): (KJS::DateProtoFuncGetUTCDate::callAsFunction): (KJS::DateProtoFuncGetDay::callAsFunction): (KJS::DateProtoFuncGetUTCDay::callAsFunction): (KJS::DateProtoFuncGetHours::callAsFunction): (KJS::DateProtoFuncGetUTCHours::callAsFunction): (KJS::DateProtoFuncGetMinutes::callAsFunction): (KJS::DateProtoFuncGetUTCMinutes::callAsFunction): (KJS::DateProtoFuncGetSeconds::callAsFunction): (KJS::DateProtoFuncGetUTCSeconds::callAsFunction): (KJS::DateProtoFuncGetMilliSeconds::callAsFunction): (KJS::DateProtoFuncGetUTCMilliseconds::callAsFunction): (KJS::DateProtoFuncGetTimezoneOffset::callAsFunction): (KJS::DateProtoFuncSetTime::callAsFunction): (KJS::DateProtoFuncSetMilliSeconds::callAsFunction): (KJS::DateProtoFuncSetUTCMilliseconds::callAsFunction): (KJS::DateProtoFuncSetSeconds::callAsFunction): (KJS::DateProtoFuncSetUTCSeconds::callAsFunction): (KJS::DateProtoFuncSetMinutes::callAsFunction): (KJS::DateProtoFuncSetUTCMinutes::callAsFunction): (KJS::DateProtoFuncSetHours::callAsFunction): (KJS::DateProtoFuncSetUTCHours::callAsFunction): (KJS::DateProtoFuncSetDate::callAsFunction): (KJS::DateProtoFuncSetUTCDate::callAsFunction): (KJS::DateProtoFuncSetMonth::callAsFunction): (KJS::DateProtoFuncSetUTCMonth::callAsFunction): (KJS::DateProtoFuncSetFullYear::callAsFunction): (KJS::DateProtoFuncSetUTCFullYear::callAsFunction): (KJS::DateProtoFuncSetYear::callAsFunction): (KJS::DateProtoFuncGetYear::callAsFunction):
  • kjs/date_object.h:
  • kjs/lookup.cpp: (KJS::Lookup::find):
  • kjs/lookup.h: (KJS::HashEntry::): (KJS::staticFunctionGetter): (KJS::staticValueGetter): (KJS::getStaticPropertySlot): (KJS::getStaticFunctionSlot): (KJS::lookupPut):
  • kjs/math_object.cpp: (KJS::MathObjectImp::getOwnPropertySlot): (KJS::MathProtoFuncAbs::callAsFunction): (KJS::MathProtoFuncACos::callAsFunction): (KJS::MathProtoFuncASin::callAsFunction): (KJS::MathProtoFuncATan::callAsFunction): (KJS::MathProtoFuncATan2::callAsFunction): (KJS::MathProtoFuncCeil::callAsFunction): (KJS::MathProtoFuncCos::callAsFunction): (KJS::MathProtoFuncExp::callAsFunction): (KJS::MathProtoFuncFloor::callAsFunction): (KJS::MathProtoFuncLog::callAsFunction): (KJS::MathProtoFuncMax::callAsFunction): (KJS::MathProtoFuncMin::callAsFunction): (KJS::MathProtoFuncPow::callAsFunction): (KJS::MathProtoFuncRandom::callAsFunction): (KJS::MathProtoFuncRound::callAsFunction): (KJS::MathProtoFuncSin::callAsFunction): (KJS::MathProtoFuncSqrt::callAsFunction): (KJS::MathProtoFuncTan::callAsFunction):
  • kjs/math_object.h: (KJS::MathObjectImp::classInfo): (KJS::MathObjectImp::):
  • kjs/string_object.cpp: (KJS::StringPrototype::getOwnPropertySlot): (KJS::StringProtoFuncToString::callAsFunction): (KJS::StringProtoFuncValueOf::callAsFunction): (KJS::StringProtoFuncCharAt::callAsFunction): (KJS::StringProtoFuncCharCodeAt::callAsFunction): (KJS::StringProtoFuncConcat::callAsFunction): (KJS::StringProtoFuncIndexOf::callAsFunction): (KJS::StringProtoFuncLastIndexOf::callAsFunction): (KJS::StringProtoFuncMatch::callAsFunction): (KJS::StringProtoFuncSearch::callAsFunction): (KJS::StringProtoFuncReplace::callAsFunction): (KJS::StringProtoFuncSlice::callAsFunction): (KJS::StringProtoFuncSplit::callAsFunction): (KJS::StringProtoFuncSubstr::callAsFunction): (KJS::StringProtoFuncSubstring::callAsFunction): (KJS::StringProtoFuncToLowerCase::callAsFunction): (KJS::StringProtoFuncToUpperCase::callAsFunction): (KJS::StringProtoFuncToLocaleLowerCase::callAsFunction): (KJS::StringProtoFuncToLocaleUpperCase::callAsFunction): (KJS::StringProtoFuncLocaleCompare::callAsFunction): (KJS::StringProtoFuncBig::callAsFunction): (KJS::StringProtoFuncSmall::callAsFunction): (KJS::StringProtoFuncBlink::callAsFunction): (KJS::StringProtoFuncBold::callAsFunction): (KJS::StringProtoFuncFixed::callAsFunction): (KJS::StringProtoFuncItalics::callAsFunction): (KJS::StringProtoFuncStrike::callAsFunction): (KJS::StringProtoFuncSub::callAsFunction): (KJS::StringProtoFuncSup::callAsFunction): (KJS::StringProtoFuncFontcolor::callAsFunction): (KJS::StringProtoFuncFontsize::callAsFunction): (KJS::StringProtoFuncAnchor::callAsFunction): (KJS::StringProtoFuncLink::callAsFunction):
  • kjs/string_object.h:

WebCore:

Reviewed by Darin.

Convert JavaScript internal function objects to use one class per
function. This avoids a switch statement inside what used to be
the shared function classes and will allow Shark to better analyze
the code.

To make this switch, the value property of the HashEntry was changed
to a union of an intptr_t (which is used to continue handle valueGetters)
and function pointer which points to a static constructor for the
individual new function objects.

SunSpider claims this is a 0.5% speedup.

  • On the WebCore side, I updated CodeGeneratorJS.pm to generate the new classes and hand updated the remain non-generated (groan) classes.
  • bindings/js/JSDOMWindowCustom.cpp: (WebCore::JSDOMWindow::customGetOwnPropertySlot):
  • bindings/js/JSEventTargetNode.cpp: (WebCore::JSEventTargetNodePrototypeFunctionAddEventListener::callAsFunction): (WebCore::JSEventTargetNodePrototypeFunctionRemoveEventListener::callAsFunction): (WebCore::JSEventTargetNodePrototypeFunctionDispatchEvent::callAsFunction):
  • bindings/js/JSEventTargetNode.h:
  • bindings/js/JSHTMLInputElementBase.cpp: (WebCore::JSHTMLInputElementBaseFunctionSetSelectionRange::callAsFunction): (WebCore::JSHTMLInputElementBase::getOwnPropertySlot):
  • bindings/js/JSHTMLInputElementBase.h: (WebCore::JSHTMLInputElementBase::):
  • bindings/js/JSXMLHttpRequest.cpp: (KJS::JSXMLHttpRequestPrototypeFunctionAbort::callAsFunction): (KJS::JSXMLHttpRequestPrototypeFunctionGetAllResponseHeaders::callAsFunction): (KJS::JSXMLHttpRequestPrototypeFunctionGetResponseHeader::callAsFunction): (KJS::JSXMLHttpRequestPrototypeFunctionOpen::callAsFunction): (KJS::JSXMLHttpRequestPrototypeFunctionSend::callAsFunction): (KJS::JSXMLHttpRequestPrototypeFunctionSetRequestHeader::callAsFunction): (KJS::JSXMLHttpRequestPrototypeFunctionOverrideMIMEType::callAsFunction): (KJS::JSXMLHttpRequestPrototypeFunctionAddEventListener::callAsFunction): (KJS::JSXMLHttpRequestPrototypeFunctionRemoveEventListener::callAsFunction): (KJS::JSXMLHttpRequestPrototypeFunctionDispatchEvent::callAsFunction):
  • bindings/js/JSXMLHttpRequest.h: (KJS::JSXMLHttpRequest::impl):
  • bindings/js/JSXSLTProcessor.cpp: (KJS::JSXSLTProcessorPrototypeFunctionImportStylesheet::callAsFunction): (KJS::JSXSLTProcessorPrototypeFunctionTransformToFragment::callAsFunction): (KJS::JSXSLTProcessorPrototypeFunctionTransformToDocument::callAsFunction): (KJS::JSXSLTProcessorPrototypeFunctionSetParameter::callAsFunction): (KJS::JSXSLTProcessorPrototypeFunctionGetParameter::callAsFunction): (KJS::JSXSLTProcessorPrototypeFunctionRemoveParameter::callAsFunction): (KJS::JSXSLTProcessorPrototypeFunctionClearParameters::callAsFunction): (KJS::JSXSLTProcessorPrototypeFunctionReset::callAsFunction):
  • bindings/js/JSXSLTProcessor.h:
  • bindings/js/kjs_events.cpp: (WebCore::JSClipboardPrototypeFunctionClearData::callAsFunction): (WebCore::JSClipboardPrototypeFunctionGetData::callAsFunction): (WebCore::JSClipboardPrototypeFunctionSetData::callAsFunction): (WebCore::JSClipboardPrototypeFunctionSetDragImage::callAsFunction):
  • bindings/js/kjs_events.h:
  • bindings/js/kjs_navigator.cpp: (KJS::Plugins::): (KJS::Navigator::getOwnPropertySlot): (KJS::Plugins::getOwnPropertySlot): (KJS::PluginsFunctionRefresh::callAsFunction): (KJS::NavigatorProtoFuncJavaEnabled::callAsFunction):
  • bindings/js/kjs_navigator.h: (KJS::Navigator::):
  • bindings/js/kjs_window.cpp: (KJS::Window::getOwnPropertySlot): (KJS::Window::put): (KJS::WindowProtoFuncAToB::callAsFunction): (KJS::WindowProtoFuncBToA::callAsFunction): (KJS::WindowProtoFuncOpen::callAsFunction): (KJS::WindowProtoFuncScrollBy::callAsFunction): (KJS::WindowProtoFuncScrollTo::callAsFunction): (KJS::WindowProtoFuncMoveBy::callAsFunction): (KJS::WindowProtoFuncMoveTo::callAsFunction): (KJS::WindowProtoFuncResizeBy::callAsFunction): (KJS::WindowProtoFuncResizeTo::callAsFunction): (KJS::WindowProtoFuncSetTimeout::callAsFunction): (KJS::WindowProtoFuncClearTimeout::callAsFunction): (KJS::WindowProtoFuncSetInterval::callAsFunction): (KJS::WindowProtoFuncAddEventListener::callAsFunction): (KJS::WindowProtoFuncRemoveEventListener::callAsFunction): (KJS::WindowProtoFuncShowModalDialog::callAsFunction): (KJS::WindowProtoFuncNotImplemented::callAsFunction): (KJS::Location::getOwnPropertySlot): (KJS::Location::put): (KJS::LocationProtoFuncReplace::callAsFunction): (KJS::LocationProtoFuncReload::callAsFunction): (KJS::LocationProtoFuncAssign::callAsFunction): (KJS::LocationProtoFuncToString::callAsFunction):
  • bindings/js/kjs_window.h: (KJS::Window::):
  • bindings/scripts/CodeGeneratorJS.pm:
File:
1 edited

Legend:

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

    r27474 r27608  
    4141/* Source for array_object.lut.h
    4242@begin arrayTable 16
    43   toString       ArrayProtoFunc::ToString       DontEnum|Function 0
    44   toLocaleString ArrayProtoFunc::ToLocaleString DontEnum|Function 0
    45   concat         ArrayProtoFunc::Concat         DontEnum|Function 1
    46   join           ArrayProtoFunc::Join           DontEnum|Function 1
    47   pop            ArrayProtoFunc::Pop            DontEnum|Function 0
    48   push           ArrayProtoFunc::Push           DontEnum|Function 1
    49   reverse        ArrayProtoFunc::Reverse        DontEnum|Function 0
    50   shift          ArrayProtoFunc::Shift          DontEnum|Function 0
    51   slice          ArrayProtoFunc::Slice          DontEnum|Function 2
    52   sort           ArrayProtoFunc::Sort           DontEnum|Function 1
    53   splice         ArrayProtoFunc::Splice         DontEnum|Function 2
    54   unshift        ArrayProtoFunc::UnShift        DontEnum|Function 1
    55   every          ArrayProtoFunc::Every          DontEnum|Function 1
    56   forEach        ArrayProtoFunc::ForEach        DontEnum|Function 1
    57   some           ArrayProtoFunc::Some           DontEnum|Function 1
    58   indexOf        ArrayProtoFunc::IndexOf        DontEnum|Function 1
    59   lastIndexOf    ArrayProtoFunc::LastIndexOf    DontEnum|Function 1
    60   filter         ArrayProtoFunc::Filter         DontEnum|Function 1
    61   map            ArrayProtoFunc::Map            DontEnum|Function 1
     43  toString       &ArrayProtoFuncToString::create       DontEnum|Function 0
     44  toLocaleString &ArrayProtoFuncToLocaleString::create DontEnum|Function 0
     45  concat         &ArrayProtoFuncConcat::create         DontEnum|Function 1
     46  join           &ArrayProtoFuncJoin::create           DontEnum|Function 1
     47  pop            &ArrayProtoFuncPop::create            DontEnum|Function 0
     48  push           &ArrayProtoFuncPush::create           DontEnum|Function 1
     49  reverse        &ArrayProtoFuncReverse::create        DontEnum|Function 0
     50  shift          &ArrayProtoFuncShift::create          DontEnum|Function 0
     51  slice          &ArrayProtoFuncSlice::create          DontEnum|Function 2
     52  sort           &ArrayProtoFuncSort::create           DontEnum|Function 1
     53  splice         &ArrayProtoFuncSplice::create         DontEnum|Function 2
     54  unshift        &ArrayProtoFuncUnShift::create        DontEnum|Function 1
     55  every          &ArrayProtoFuncEvery::create          DontEnum|Function 1
     56  forEach        &ArrayProtoFuncForEach::create        DontEnum|Function 1
     57  some           &ArrayProtoFuncSome::create           DontEnum|Function 1
     58  indexOf        &ArrayProtoFuncIndexOf::create        DontEnum|Function 1
     59  lastIndexOf    &ArrayProtoFuncLastIndexOf::create    DontEnum|Function 1
     60  filter         &ArrayProtoFuncFilter::create         DontEnum|Function 1
     61  map            &ArrayProtoFuncMap::create            DontEnum|Function 1
    6262@end
    6363*/
     
    7171bool ArrayPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
    7272{
    73   return getStaticFunctionSlot<ArrayProtoFunc, ArrayInstance>(exec, &arrayTable, this, propertyName, slot);
    74 }
    75 
    76 // ------------------------------ ArrayProtoFunc ----------------------------
    77 
    78 ArrayProtoFunc::ArrayProtoFunc(ExecState* exec, int i, int len, const Identifier& name)
    79   : InternalFunctionImp(static_cast<FunctionPrototype*>
    80                         (exec->lexicalInterpreter()->builtinFunctionPrototype()), name)
    81   , id(i)
    82 {
    83   put(exec, exec->propertyNames().length, jsNumber(len), DontDelete | ReadOnly | DontEnum);
    84 }
    85 
    86 static JSValue *getProperty(ExecState *exec, JSObject *obj, unsigned index)
     73  return getStaticFunctionSlot<ArrayInstance>(exec, &arrayTable, this, propertyName, slot);
     74}
     75
     76
     77// ------------------------------ Array Functions ----------------------------
     78
     79// Helper function
     80static JSValue* getProperty(ExecState* exec, JSObject* obj, unsigned index)
    8781{
    8882    PropertySlot slot;
    8983    if (!obj->getPropertySlot(exec, index, slot))
    90         return NULL;
     84        return 0;
    9185    return slot.getValue(exec, obj, index);
    9286}
    9387
    94 // ECMA 15.4.4
    95 JSValue* ArrayProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
    96 {
    97   unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
    98 
    99   JSValue *result = 0; // work around gcc 4.0 bug in uninitialized variable warning
    100  
    101   switch (id) {
    102   case ToLocaleString:
    103   case ToString:
    104 
     88JSValue* ArrayProtoFuncToString::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
     89{
    10590    if (!thisObj->inherits(&ArrayInstance::info))
    106       return throwError(exec, TypeError);
    107 
    108     // fall through
    109   case Join: {
     91        return throwError(exec, TypeError);
     92
    11093    static HashSet<JSObject*> visitedElems;
    11194    static const UString* empty = new UString("");
     
    117100    UString str = *empty;
    118101
    119     if (id == Join && !args[0]->isUndefined())
    120         separator = args[0]->toString(exec);
     102    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
    121103    for (unsigned int k = 0; k < length; k++) {
    122104        if (k >= 1)
     
    132114            continue;
    133115
    134         bool fallback = false;
    135         if (id == ToLocaleString) {
    136             JSObject* o = element->toObject(exec);
    137             JSValue* conversionFunction = o->get(exec, exec->propertyNames().toLocaleString);
    138             if (conversionFunction->isObject() && static_cast<JSObject*>(conversionFunction)->implementsCall()) {
    139                 List args;
    140                 str += static_cast<JSObject*>(conversionFunction)->call(exec, o, args)->toString(exec);
    141             } else {
    142                 // try toString() fallback
    143                 fallback = true;
    144             }
    145         }
    146 
    147         if (id == ToString || id == Join || fallback)
    148             str += element->toString(exec);
     116        str += element->toString(exec);
    149117
    150118        if (str.isNull()) {
     
    157125    }
    158126    visitedElems.remove(thisObj);
    159     result = jsString(str);
    160     break;
    161   }
    162   case Concat: {
    163     JSObject *arr = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec,List::empty()));
     127    return jsString(str);
     128}
     129
     130JSValue* ArrayProtoFuncToLocaleString::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
     131{
     132    if (!thisObj->inherits(&ArrayInstance::info))
     133        return throwError(exec, TypeError);
     134
     135    static HashSet<JSObject*> visitedElems;
     136    static const UString* empty = new UString("");
     137    static const UString* comma = new UString(",");
     138    bool alreadyVisited = !visitedElems.add(thisObj).second;
     139    if (alreadyVisited)
     140        return jsString(*empty);
     141    UString separator = *comma;
     142    UString str = *empty;
     143
     144    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
     145    for (unsigned int k = 0; k < length; k++) {
     146        if (k >= 1)
     147            str += separator;
     148        if (str.isNull()) {
     149            JSObject *error = Error::create(exec, GeneralError, "Out of memory");
     150            exec->setException(error);
     151            break;
     152        }
     153
     154        JSValue* element = thisObj->get(exec, k);
     155        if (element->isUndefinedOrNull())
     156            continue;
     157
     158        bool fallback = false;
     159        JSObject* o = element->toObject(exec);
     160        JSValue* conversionFunction = o->get(exec, exec->propertyNames().toLocaleString);
     161        if (conversionFunction->isObject() && static_cast<JSObject*>(conversionFunction)->implementsCall()) {
     162            List args;
     163            str += static_cast<JSObject*>(conversionFunction)->call(exec, o, args)->toString(exec);
     164        } else {
     165            // try toString() fallback
     166            fallback = true;
     167        }
     168
     169        if (fallback)
     170            str += element->toString(exec);
     171
     172        if (str.isNull()) {
     173            JSObject *error = Error::create(exec, GeneralError, "Out of memory");
     174            exec->setException(error);
     175        }
     176
     177        if (exec->hadException())
     178            break;
     179    }
     180    visitedElems.remove(thisObj);
     181    return jsString(str);
     182}
     183
     184JSValue* ArrayProtoFuncJoin::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
     185{
     186    static HashSet<JSObject*> visitedElems;
     187    static const UString* empty = new UString("");
     188    static const UString* comma = new UString(",");
     189    bool alreadyVisited = !visitedElems.add(thisObj).second;
     190    if (alreadyVisited)
     191        return jsString(*empty);
     192    UString separator = *comma;
     193    UString str = *empty;
     194
     195    if (!args[0]->isUndefined())
     196        separator = args[0]->toString(exec);
     197
     198    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
     199    for (unsigned int k = 0; k < length; k++) {
     200        if (k >= 1)
     201            str += separator;
     202        if (str.isNull()) {
     203            JSObject *error = Error::create(exec, GeneralError, "Out of memory");
     204            exec->setException(error);
     205            break;
     206        }
     207
     208        JSValue* element = thisObj->get(exec, k);
     209        if (element->isUndefinedOrNull())
     210            continue;
     211
     212        str += element->toString(exec);
     213
     214        if (str.isNull()) {
     215            JSObject *error = Error::create(exec, GeneralError, "Out of memory");
     216            exec->setException(error);
     217        }
     218
     219        if (exec->hadException())
     220            break;
     221    }
     222    visitedElems.remove(thisObj);
     223    return jsString(str);
     224}
     225
     226JSValue* ArrayProtoFuncConcat::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
     227{
     228    JSObject* arr = static_cast<JSObject*>(exec->lexicalInterpreter()->builtinArray()->construct(exec, List::empty()));
    164229    int n = 0;
    165230    JSValue *curArg = thisObj;
     
    167232    List::const_iterator it = args.begin();
    168233    List::const_iterator end = args.end();
     234    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
    169235    for (;;) {
    170       if (curArg->isObject() &&
    171           curObj->inherits(&ArrayInstance::info)) {
    172         unsigned int k = 0;
    173         // Older versions tried to optimize out getting the length of thisObj
    174         // by checking for n != 0, but that doesn't work if thisObj is an empty array.
    175         length = curObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
    176         while (k < length) {
    177           if (JSValue *v = getProperty(exec, curObj, k))
    178             arr->put(exec, n, v);
    179           n++;
    180           k++;
    181         }
    182       } else {
    183         arr->put(exec, n, curArg);
    184         n++;
    185       }
    186       if (it == end)
    187         break;
    188       curArg = *it;
    189       curObj = static_cast<JSObject*>(curArg); // may be 0
    190       ++it;
     236        if (curArg->isObject() &&
     237            curObj->inherits(&ArrayInstance::info)) {
     238            unsigned int k = 0;
     239            // Older versions tried to optimize out getting the length of thisObj
     240            // by checking for n != 0, but that doesn't work if thisObj is an empty array.
     241            length = curObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
     242            while (k < length) {
     243                if (JSValue *v = getProperty(exec, curObj, k))
     244                    arr->put(exec, n, v);
     245                n++;
     246                k++;
     247            }
     248        } else {
     249            arr->put(exec, n, curArg);
     250            n++;
     251        }
     252        if (it == end)
     253            break;
     254        curArg = *it;
     255        curObj = static_cast<JSObject*>(curArg); // may be 0
     256        ++it;
    191257    }
    192258    arr->put(exec, exec->propertyNames().length, jsNumber(n), DontEnum | DontDelete);
    193 
    194     result = arr;
    195     break;
    196   }
    197   case Pop:{
     259    return arr;
     260}
     261
     262JSValue* ArrayProtoFuncPop::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
     263{
     264    JSValue* result = 0;
     265    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
    198266    if (length == 0) {
    199267      thisObj->put(exec, exec->propertyNames().length, jsNumber(length), DontEnum | DontDelete);
     
    203271      thisObj->put(exec, exec->propertyNames().length, jsNumber(length - 1), DontEnum | DontDelete);
    204272    }
    205     break;
    206   }
    207   case Push: {
     273    return result;
     274}
     275
     276JSValue* ArrayProtoFuncPush::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
     277{
     278    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
    208279    for (unsigned int n = 0; n < args.size(); n++)
    209       thisObj->put(exec, length + n, args[n]);
     280        thisObj->put(exec, length + n, args[n]);
    210281    length += args.size();
    211282    thisObj->put(exec, exec->propertyNames().length, jsNumber(length), DontEnum | DontDelete);
    212     result = jsNumber(length);
    213     break;
    214   }
    215   case Reverse: {
    216 
     283    return jsNumber(length);
     284}
     285
     286JSValue* ArrayProtoFuncReverse::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
     287{
     288    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
    217289    unsigned int middle = length / 2;
    218290
    219291    for (unsigned int k = 0; k < middle; k++) {
    220       unsigned lk1 = length - k - 1;
    221       JSValue *obj2 = getProperty(exec, thisObj, lk1);
    222       JSValue *obj = getProperty(exec, thisObj, k);
    223 
    224       if (obj2)
    225         thisObj->put(exec, k, obj2);
    226       else
    227         thisObj->deleteProperty(exec, k);
    228 
    229       if (obj)
    230         thisObj->put(exec, lk1, obj);
    231       else
    232         thisObj->deleteProperty(exec, lk1);
    233     }
    234     result = thisObj;
    235     break;
    236   }
    237   case Shift: {
     292        unsigned lk1 = length - k - 1;
     293        JSValue *obj2 = getProperty(exec, thisObj, lk1);
     294        JSValue *obj = getProperty(exec, thisObj, k);
     295
     296        if (obj2)
     297            thisObj->put(exec, k, obj2);
     298        else
     299            thisObj->deleteProperty(exec, k);
     300
     301        if (obj)
     302            thisObj->put(exec, lk1, obj);
     303        else
     304            thisObj->deleteProperty(exec, lk1);
     305    }
     306    return thisObj;
     307}
     308
     309JSValue* ArrayProtoFuncShift::callAsFunction(ExecState* exec, JSObject* thisObj, const List&)
     310{
     311    JSValue* result = 0;
     312
     313    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
    238314    if (length == 0) {
    239315      thisObj->put(exec, exec->propertyNames().length, jsNumber(length), DontEnum | DontDelete);
     
    250326      thisObj->put(exec, exec->propertyNames().length, jsNumber(length - 1), DontEnum | DontDelete);
    251327    }
    252     break;
    253   }
    254   case Slice: {
     328    return result;
     329}
     330
     331JSValue* ArrayProtoFuncSlice::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
     332{
    255333    // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10
    256334
    257335    // We return a new array
    258336    JSObject *resObj = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec,List::empty()));
    259     result = resObj;
     337    JSValue* result = resObj;
    260338    double begin = args[0]->toInteger(exec);
     339    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
    261340    if (begin >= 0) {
    262       if (begin > length)
    263         begin = length;
     341        if (begin > length)
     342            begin = length;
    264343    } else {
    265       begin += length;
    266       if (begin < 0)
    267         begin = 0;
     344        begin += length;
     345        if (begin < 0)
     346            begin = 0;
    268347    }
    269348    double end;
    270349    if (args[1]->isUndefined())
    271       end = length;
     350        end = length;
    272351    else {
    273       end = args[1]->toInteger(exec);
    274       if (end < 0) {
    275         end += length;
    276         if (end < 0)
    277           end = 0;
    278       } else {
    279         if (end > length)
    280           end = length;
    281       }
     352        end = args[1]->toInteger(exec);
     353        if (end < 0) {
     354            end += length;
     355            if (end < 0)
     356                end = 0;
     357        } else {
     358            if (end > length)
     359                end = length;
     360        }
    282361    }
    283362
     
    286365    int e = static_cast<int>(end);
    287366    for(int k = b; k < e; k++, n++) {
    288       if (JSValue *v = getProperty(exec, thisObj, k))
    289         resObj->put(exec, n, v);
     367        if (JSValue *v = getProperty(exec, thisObj, k))
     368            resObj->put(exec, n, v);
    290369    }
    291370    resObj->put(exec, exec->propertyNames().length, jsNumber(n), DontEnum | DontDelete);
    292     break;
    293   }
    294   case Sort:{
     371    return result;
     372}
     373
     374JSValue* ArrayProtoFuncSort::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
     375{
    295376#if 0
    296377    printf("KJS Array::Sort length=%d\n", length);
     
    311392      else
    312393        ((ArrayInstance *)thisObj)->sort(exec);
    313       result = thisObj;
    314       break;
    315     }
     394      return thisObj;
     395    }
     396
     397    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
    316398
    317399    if (length == 0) {
    318400      thisObj->put(exec, exec->propertyNames().length, jsNumber(0), DontEnum | DontDelete);
    319       result = thisObj;
    320       break;
     401      return thisObj;
    321402    }
    322403
     
    357438            thisObj->put( exec, themin, iObj );
    358439          }
    359       }
     440    }
    360441#if 0
    361442    printf("KJS Array::Sort -- Resulting array:\n");
     
    363444      printf("KJS Array::Sort: %d: %s\n", i, thisObj->get(exec, i)->toString(exec).ascii() );
    364445#endif
    365     result = thisObj;
    366     break;
    367   }
    368   case Splice: {
     446    return thisObj;
     447}
     448
     449JSValue* ArrayProtoFuncSplice::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
     450{
    369451    // 15.4.4.12 - oh boy this is huge
    370     JSObject *resObj = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec,List::empty()));
    371     result = resObj;
     452    JSObject *resObj = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec, List::empty()));
     453    JSValue* result = resObj;
     454    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
    372455    int begin = args[0]->toUInt32(exec);
    373456    if ( begin < 0 )
     
    415498    }
    416499    thisObj->put(exec, exec->propertyNames().length, jsNumber(length - deleteCount + additionalArgs), DontEnum | DontDelete);
    417     break;
    418   }
    419   case UnShift: { // 15.4.4.13
     500    return result;
     501}
     502
     503JSValue* ArrayProtoFuncUnShift::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
     504{
     505    // 15.4.4.13
     506    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
    420507    unsigned int nrArgs = args.size();
    421508    for ( unsigned int k = length; k > 0; --k )
     
    428515    for ( unsigned int k = 0; k < nrArgs; ++k )
    429516      thisObj->put(exec, k, args[k]);
    430     result = jsNumber(length + nrArgs);
     517    JSValue* result = jsNumber(length + nrArgs);
    431518    thisObj->put(exec, exec->propertyNames().length, result, DontEnum | DontDelete);
    432     break;
    433   }
    434   case Filter:
    435   case Map: {
     519    return result;
     520}
     521
     522JSValue* ArrayProtoFuncFilter::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
     523{
     524    JSObject* eachFunction = args[0]->toObject(exec);
     525   
     526    if (!eachFunction->implementsCall())
     527        return throwError(exec, TypeError);
     528   
     529    JSObject *applyThis = args[1]->isUndefinedOrNull() ? exec->dynamicInterpreter()->globalObject() :  args[1]->toObject(exec);
     530    JSObject *resultArray = static_cast<JSObject*>(exec->lexicalInterpreter()->builtinArray()->construct(exec, List::empty()));
     531
     532    unsigned filterIndex = 0;
     533    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
     534    for (unsigned k = 0; k < length && !exec->hadException(); ++k) {
     535        PropertySlot slot;
     536
     537        if (!thisObj->getPropertySlot(exec, k, slot))
     538            continue;
     539       
     540        JSValue *v = slot.getValue(exec, thisObj, k);
     541       
     542        List eachArguments;
     543       
     544        eachArguments.append(v);
     545        eachArguments.append(jsNumber(k));
     546        eachArguments.append(thisObj);
     547     
     548        JSValue *result = eachFunction->call(exec, applyThis, eachArguments);
     549     
     550        if (result->toBoolean(exec))
     551            resultArray->put(exec, filterIndex++, v);
     552    }
     553    return resultArray;
     554}
     555
     556JSValue* ArrayProtoFuncMap::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
     557{
     558    JSObject* eachFunction = args[0]->toObject(exec);
     559    if (!eachFunction->implementsCall())
     560        return throwError(exec, TypeError);
     561   
     562    JSObject *applyThis = args[1]->isUndefinedOrNull() ? exec->dynamicInterpreter()->globalObject() :  args[1]->toObject(exec);
     563
     564    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
     565
     566    List mapArgs;
     567    mapArgs.append(jsNumber(length));
     568    JSObject* resultArray = static_cast<JSObject*>(exec->lexicalInterpreter()->builtinArray()->construct(exec, mapArgs));
     569
     570    for (unsigned k = 0; k < length && !exec->hadException(); ++k) {
     571        PropertySlot slot;
     572        if (!thisObj->getPropertySlot(exec, k, slot))
     573            continue;
     574
     575        JSValue *v = slot.getValue(exec, thisObj, k);
     576
     577        List eachArguments;
     578
     579        eachArguments.append(v);
     580        eachArguments.append(jsNumber(k));
     581        eachArguments.append(thisObj);
     582
     583        JSValue *result = eachFunction->call(exec, applyThis, eachArguments);
     584        resultArray->put(exec, k, result);
     585    }
     586
     587    return resultArray;
     588}
     589
     590// Documentation for these three is available at:
     591// http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:every
     592// http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:forEach
     593// http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:some
     594
     595JSValue* ArrayProtoFuncEvery::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
     596{
    436597    JSObject *eachFunction = args[0]->toObject(exec);
    437598   
    438599    if (!eachFunction->implementsCall())
    439       return throwError(exec, TypeError);
    440    
    441     JSObject *applyThis = args[1]->isUndefinedOrNull() ? exec->dynamicInterpreter()->globalObject() :  args[1]->toObject(exec);
    442     JSObject *resultArray;
    443    
    444     if (id == Filter)
    445       resultArray = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec, List::empty()));
    446     else {
    447       List args;
    448       args.append(jsNumber(length));
    449       resultArray = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec, args));
    450     }
    451    
    452     unsigned filterIndex = 0;
    453     for (unsigned k = 0; k < length && !exec->hadException(); ++k) {
    454       PropertySlot slot;
    455 
    456       if (!thisObj->getPropertySlot(exec, k, slot))
    457          continue;
    458        
    459       JSValue *v = slot.getValue(exec, thisObj, k);
    460      
    461       List eachArguments;
    462      
    463       eachArguments.append(v);
    464       eachArguments.append(jsNumber(k));
    465       eachArguments.append(thisObj);
    466      
    467       JSValue *result = eachFunction->call(exec, applyThis, eachArguments);
    468      
    469       if (id == Map)
    470         resultArray->put(exec, k, result);
    471       else if (result->toBoolean(exec))
    472         resultArray->put(exec, filterIndex++, v);
    473     }
    474    
    475     return resultArray;
    476   }
    477   case Every:
    478   case ForEach:
    479   case Some: {
    480     //Documentation for these three is available at:
    481     //http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:every
    482     //http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:forEach
    483     //http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:some
    484    
    485     JSObject *eachFunction = args[0]->toObject(exec);
    486    
    487     if (!eachFunction->implementsCall())
    488       return throwError(exec, TypeError);
     600        return throwError(exec, TypeError);
    489601   
    490602    JSObject *applyThis = args[1]->isUndefinedOrNull() ? exec->dynamicInterpreter()->globalObject() :  args[1]->toObject(exec);
    491603   
    492     if (id == Some || id == Every)
    493       result = jsBoolean(id == Every);
    494     else
    495       result = jsUndefined();
     604    JSValue* result = jsBoolean(true);
    496605   
     606    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
    497607    for (unsigned k = 0; k < length && !exec->hadException(); ++k) {
    498       PropertySlot slot;
     608        PropertySlot slot;
     609         
     610        if (!thisObj->getPropertySlot(exec, k, slot))
     611            continue;
     612     
     613        List eachArguments;
    499614       
    500       if (!thisObj->getPropertySlot(exec, k, slot))
    501         continue;
     615        eachArguments.append(slot.getValue(exec, thisObj, k));
     616        eachArguments.append(jsNumber(k));
     617        eachArguments.append(thisObj);
    502618     
    503       List eachArguments;
     619        bool predicateResult = eachFunction->call(exec, applyThis, eachArguments)->toBoolean(exec);
    504620     
    505       eachArguments.append(slot.getValue(exec, thisObj, k));
    506       eachArguments.append(jsNumber(k));
    507       eachArguments.append(thisObj);
    508      
    509       bool predicateResult = eachFunction->call(exec, applyThis, eachArguments)->toBoolean(exec);
    510      
    511       if (id == Every && !predicateResult) {
    512         result = jsBoolean(false);
    513         break;
    514       }
    515       if (id == Some && predicateResult) {
    516         result = jsBoolean(true);
    517         break;
    518       }
    519     }
    520     break;
    521   }
    522 
    523   case IndexOf: {
     621        if (!predicateResult) {
     622            result = jsBoolean(false);
     623            break;
     624        }
     625    }
     626
     627    return result;
     628}
     629
     630JSValue* ArrayProtoFuncForEach::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
     631{
     632    JSObject* eachFunction = args[0]->toObject(exec);
     633
     634    if (!eachFunction->implementsCall())
     635        return throwError(exec, TypeError);
     636
     637    JSObject* applyThis = args[1]->isUndefinedOrNull() ? exec->dynamicInterpreter()->globalObject() :  args[1]->toObject(exec);
     638
     639    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
     640    for (unsigned k = 0; k < length && !exec->hadException(); ++k) {
     641        PropertySlot slot;
     642        if (!thisObj->getPropertySlot(exec, k, slot))
     643            continue;
     644
     645        List eachArguments;
     646        eachArguments.append(slot.getValue(exec, thisObj, k));
     647        eachArguments.append(jsNumber(k));
     648        eachArguments.append(thisObj);
     649
     650        eachFunction->call(exec, applyThis, eachArguments);
     651    }
     652    return jsUndefined();
     653}
     654
     655JSValue* ArrayProtoFuncSome::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
     656{
     657    JSObject* eachFunction = args[0]->toObject(exec);
     658
     659    if (!eachFunction->implementsCall())
     660        return throwError(exec, TypeError);
     661
     662    JSObject* applyThis = args[1]->isUndefinedOrNull() ? exec->dynamicInterpreter()->globalObject() :  args[1]->toObject(exec);
     663
     664    JSValue* result = jsBoolean(false);
     665
     666    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
     667    for (unsigned k = 0; k < length && !exec->hadException(); ++k) {
     668        PropertySlot slot;
     669        if (!thisObj->getPropertySlot(exec, k, slot))
     670            continue;
     671
     672        List eachArguments;
     673        eachArguments.append(slot.getValue(exec, thisObj, k));
     674        eachArguments.append(jsNumber(k));
     675        eachArguments.append(thisObj);
     676
     677        bool predicateResult = eachFunction->call(exec, applyThis, eachArguments)->toBoolean(exec);
     678
     679        if (predicateResult) {
     680            result = jsBoolean(true);
     681            break;
     682        }
     683    }
     684    return result;
     685}
     686
     687JSValue* ArrayProtoFuncIndexOf::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
     688{
    524689    // JavaScript 1.5 Extension by Mozilla
    525690    // Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf
     
    527692    unsigned index = 0;
    528693    double d = args[1]->toInteger(exec);
     694    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
    529695    if (d < 0)
    530696        d += length;
     
    546712
    547713    return jsNumber(-1);
    548   }
    549   case LastIndexOf: {
    550        // JavaScript 1.6 Extension by Mozilla
    551       // Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf
    552 
     714}
     715
     716JSValue* ArrayProtoFuncLastIndexOf::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
     717{
     718    // JavaScript 1.6 Extension by Mozilla
     719    // Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf
     720
     721    unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
    553722    int index = length - 1;
    554723    double d = args[1]->toIntegerPreserveNaN(exec);
     
    573742    return jsNumber(-1);
    574743}
    575   default:
    576     ASSERT(0);
    577     result = 0;
    578     break;
    579   }
    580   return result;
    581 }
    582744
    583745// ------------------------------ ArrayObjectImp -------------------------------
Note: See TracChangeset for help on using the changeset viewer.