Ignore:
Timestamp:
Jan 17, 2008, 11:27:33 AM (17 years ago)
Author:
[email protected]
Message:

Reviewed by Darin.

Fix for http://bugs.webkit.org/show_bug.cgi?id=16901
Convert remaining JS function objects to use the new PrototypeFunction class

  • Moves Boolean, Function, RegExp, Number, Object and Global functions to their own static function implementations so that they can be used with the PrototypeFunction class. SunSpider says this is 1.003x as fast.
  • kjs/JSGlobalObject.cpp: (KJS::JSGlobalObject::reset):
  • kjs/array_object.h:
  • kjs/bool_object.cpp: (KJS::BooleanInstance::BooleanInstance): (KJS::BooleanPrototype::BooleanPrototype): (KJS::booleanProtoFuncToString): (KJS::booleanProtoFuncValueOf): (KJS::BooleanObjectImp::BooleanObjectImp): (KJS::BooleanObjectImp::implementsConstruct): (KJS::BooleanObjectImp::construct): (KJS::BooleanObjectImp::callAsFunction):
  • kjs/bool_object.h: (KJS::BooleanInstance::classInfo):
  • kjs/error_object.cpp: (KJS::ErrorPrototype::ErrorPrototype): (KJS::errorProtoFuncToString):
  • kjs/error_object.h:
  • kjs/function.cpp: (KJS::globalFuncEval): (KJS::globalFuncParseInt): (KJS::globalFuncParseFloat): (KJS::globalFuncIsNaN): (KJS::globalFuncIsFinite): (KJS::globalFuncDecodeURI): (KJS::globalFuncDecodeURIComponent): (KJS::globalFuncEncodeURI): (KJS::globalFuncEncodeURIComponent): (KJS::globalFuncEscape): (KJS::globalFuncUnEscape): (KJS::globalFuncKJSPrint): (KJS::PrototypeFunction::PrototypeFunction):
  • kjs/function.h:
  • kjs/function_object.cpp: (KJS::FunctionPrototype::FunctionPrototype): (KJS::functionProtoFuncToString): (KJS::functionProtoFuncApply): (KJS::functionProtoFuncCall):
  • kjs/function_object.h:
  • kjs/number_object.cpp: (KJS::NumberPrototype::NumberPrototype): (KJS::numberProtoFuncToString): (KJS::numberProtoFuncToLocaleString): (KJS::numberProtoFuncValueOf): (KJS::numberProtoFuncToFixed): (KJS::numberProtoFuncToExponential): (KJS::numberProtoFuncToPrecision):
  • kjs/number_object.h: (KJS::NumberInstance::classInfo): (KJS::NumberObjectImp::classInfo): (KJS::NumberObjectImp::):
  • kjs/object_object.cpp: (KJS::ObjectPrototype::ObjectPrototype): (KJS::objectProtoFuncValueOf): (KJS::objectProtoFuncHasOwnProperty): (KJS::objectProtoFuncIsPrototypeOf): (KJS::objectProtoFuncDefineGetter): (KJS::objectProtoFuncDefineSetter): (KJS::objectProtoFuncLookupGetter): (KJS::objectProtoFuncLookupSetter): (KJS::objectProtoFuncPropertyIsEnumerable): (KJS::objectProtoFuncToLocaleString): (KJS::objectProtoFuncToString):
  • kjs/object_object.h:
  • kjs/regexp_object.cpp: (KJS::RegExpPrototype::RegExpPrototype): (KJS::regExpProtoFuncTest): (KJS::regExpProtoFuncExec): (KJS::regExpProtoFuncCompile): (KJS::regExpProtoFuncToString):
  • kjs/regexp_object.h:
File:
1 edited

Legend:

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

    r29067 r29588  
    3737#include <wtf/Assertions.h>
    3838
    39 using namespace KJS;
     39namespace KJS {
    4040
    4141// ------------------------------ FunctionPrototype -------------------------
    4242
    43 FunctionPrototype::FunctionPrototype(ExecState *exec)
    44 {
    45   static const Identifier* applyPropertyName = new Identifier("apply");
    46   static const Identifier* callPropertyName = new Identifier("call");
    47 
    48   putDirect(exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
    49   putDirectFunction(new FunctionProtoFunc(exec, this, FunctionProtoFunc::ToString, 0, exec->propertyNames().toString), DontEnum);
    50   putDirectFunction(new FunctionProtoFunc(exec, this, FunctionProtoFunc::Apply, 2, *applyPropertyName), DontEnum);
    51   putDirectFunction(new FunctionProtoFunc(exec, this, FunctionProtoFunc::Call, 1, *callPropertyName), DontEnum);
    52 }
    53 
    54 FunctionPrototype::~FunctionPrototype()
    55 {
     43static JSValue* functionProtoFuncToString(ExecState*, JSObject*, const List&);
     44static JSValue* functionProtoFuncApply(ExecState*, JSObject*, const List&);
     45static JSValue* functionProtoFuncCall(ExecState*, JSObject*, const List&);
     46
     47FunctionPrototype::FunctionPrototype(ExecState* exec)
     48{
     49    static const Identifier* applyPropertyName = new Identifier("apply");
     50    static const Identifier* callPropertyName = new Identifier("call");
     51
     52    putDirect(exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
     53
     54    putDirectFunction(new PrototypeFunction(exec, this, 0, exec->propertyNames().toString, functionProtoFuncToString), DontEnum);
     55    putDirectFunction(new PrototypeFunction(exec, this, 2, *applyPropertyName, functionProtoFuncApply), DontEnum);
     56    putDirectFunction(new PrototypeFunction(exec, this, 1, *callPropertyName, functionProtoFuncCall), DontEnum);
    5657}
    5758
    5859// ECMA 15.3.4
    59 JSValue *FunctionPrototype::callAsFunction(ExecState*, JSObject* /*thisObj*/, const List &/*args*/)
    60 {
    61   return jsUndefined();
    62 }
    63 
    64 // ------------------------------ FunctionProtoFunc -------------------------
    65 
    66 FunctionProtoFunc::FunctionProtoFunc(ExecState* exec, FunctionPrototype* funcProto, int i, int len, const Identifier& name)
    67   : InternalFunctionImp(funcProto, name)
    68   , id(i)
    69 {
    70   putDirect(exec->propertyNames().length, len, DontDelete | ReadOnly | DontEnum);
    71 }
    72 
    73 JSValue* FunctionProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, const List &args)
    74 {
    75   JSValue* result = NULL;
    76 
    77   switch (id) {
    78   case ToString:
     60JSValue* FunctionPrototype::callAsFunction(ExecState*, JSObject*, const List&)
     61{
     62    return jsUndefined();
     63}
     64
     65// Functions
     66
     67JSValue* functionProtoFuncToString(ExecState* exec, JSObject* thisObj, const List&)
     68{
    7969    if (!thisObj || !thisObj->inherits(&InternalFunctionImp::info)) {
    8070#ifndef NDEBUG
    81       fprintf(stderr,"attempted toString() call on null or non-function object\n");
     71        fprintf(stderr,"attempted toString() call on null or non-function object\n");
    8272#endif
    83       return throwError(exec, TypeError);
    84     }
     73        return throwError(exec, TypeError);
     74    }
     75
    8576    if (thisObj->inherits(&FunctionImp::info)) {
    86         FunctionImp *fi = static_cast<FunctionImp*>(thisObj);
    87         return jsString("function " + fi->functionName().ustring() + "(" +
    88                         fi->body->paramString() + ") " + fi->body->toString());
    89      } else if (thisObj->inherits(&InternalFunctionImp::info) &&
    90                 !static_cast<InternalFunctionImp*>(thisObj)->functionName().isNull()) {
    91        result = jsString("\nfunction " + static_cast<InternalFunctionImp*>(thisObj)->functionName().ustring() + "() {\n"
    92                        "    [native code]\n}\n");
    93     } else {
    94       result = jsString("[function]");
    95     }
    96     break;
    97   case Apply: {
    98     JSValue *thisArg = args[0];
    99     JSValue *argArray = args[1];
    100     JSObject *func = thisObj;
    101 
    102     if (!func->implementsCall())
    103       return throwError(exec, TypeError);
    104 
    105     JSObject *applyThis;
     77        FunctionImp* fi = static_cast<FunctionImp*>(thisObj);
     78        return jsString("function " + fi->functionName().ustring() + "(" + fi->body->paramString() + ") " + fi->body->toString());
     79    }
     80
     81    if (thisObj->inherits(&InternalFunctionImp::info) && !static_cast<InternalFunctionImp*>(thisObj)->functionName().isNull())
     82        return jsString("\nfunction " + static_cast<InternalFunctionImp*>(thisObj)->functionName().ustring() + "() {\n    [native code]\n}\n");
     83
     84    return jsString("[function]");
     85}
     86
     87JSValue* functionProtoFuncApply(ExecState* exec, JSObject* thisObj, const List& args)
     88{
     89    if (!thisObj->implementsCall())
     90        return throwError(exec, TypeError);
     91
     92    JSValue* thisArg = args[0];
     93    JSValue* argArray = args[1];
     94
     95    JSObject* applyThis;
    10696    if (thisArg->isUndefinedOrNull())
    107       applyThis = exec->dynamicGlobalObject();
     97        applyThis = exec->dynamicGlobalObject();
    10898    else
    109       applyThis = thisArg->toObject(exec);
     99        applyThis = thisArg->toObject(exec);
    110100
    111101    List applyArgs;
    112102    if (!argArray->isUndefinedOrNull()) {
    113       if (argArray->isObject() &&
    114            (static_cast<JSObject *>(argArray)->inherits(&ArrayInstance::info) ||
    115             static_cast<JSObject *>(argArray)->inherits(&Arguments::info))) {
    116 
    117         JSObject *argArrayObj = static_cast<JSObject *>(argArray);
    118         unsigned int length = argArrayObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
    119         for (unsigned int i = 0; i < length; i++)
    120           applyArgs.append(argArrayObj->get(exec,i));
    121       }
    122       else
     103        if (argArray->isObject() &&
     104            (static_cast<JSObject*>(argArray)->inherits(&ArrayInstance::info) ||
     105             static_cast<JSObject*>(argArray)->inherits(&Arguments::info))) {
     106
     107            JSObject* argArrayObj = static_cast<JSObject*>(argArray);
     108            unsigned int length = argArrayObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
     109            for (unsigned int i = 0; i < length; i++)
     110                applyArgs.append(argArrayObj->get(exec, i));
     111        } else
     112            return throwError(exec, TypeError);
     113    }
     114
     115    return thisObj->call(exec, applyThis, applyArgs);
     116}
     117
     118JSValue* functionProtoFuncCall(ExecState* exec, JSObject* thisObj, const List& args)
     119{
     120    if (!thisObj->implementsCall())
    123121        return throwError(exec, TypeError);
    124     }
    125     result = func->call(exec,applyThis,applyArgs);
    126     }
    127     break;
    128   case Call: {
    129     JSValue *thisArg = args[0];
    130     JSObject *func = thisObj;
    131 
    132     if (!func->implementsCall())
    133       return throwError(exec, TypeError);
    134 
    135     JSObject *callThis;
     122
     123    JSValue* thisArg = args[0];
     124
     125    JSObject* callThis;
    136126    if (thisArg->isUndefinedOrNull())
    137       callThis = exec->dynamicGlobalObject();
     127        callThis = exec->dynamicGlobalObject();
    138128    else
    139       callThis = thisArg->toObject(exec);
     129        callThis = thisArg->toObject(exec);
    140130
    141131    List argsTail;
    142132    args.getSlice(1, argsTail);
    143     result = func->call(exec, callThis, argsTail);
    144     }
    145     break;
    146   }
    147 
    148   return result;
     133    return thisObj->call(exec, callThis, argsTail);
    149134}
    150135
    151136// ------------------------------ FunctionObjectImp ----------------------------
    152137
    153 FunctionObjectImp::FunctionObjectImp(ExecState* exec, FunctionPrototype* funcProto)
    154   : InternalFunctionImp(funcProto)
    155 {
    156   putDirect(exec->propertyNames().prototype, funcProto, DontEnum|DontDelete|ReadOnly);
    157 
    158   // no. of arguments for constructor
    159   putDirect(exec->propertyNames().length, jsNumber(1), ReadOnly|DontDelete|DontEnum);
    160 }
    161 
    162 FunctionObjectImp::~FunctionObjectImp()
    163 {
     138FunctionObjectImp::FunctionObjectImp(ExecState* exec, FunctionPrototype* functionPrototype)
     139    : InternalFunctionImp(functionPrototype)
     140{
     141    putDirect(exec->propertyNames().prototype, functionPrototype, DontEnum | DontDelete | ReadOnly);
     142
     143    // Number of arguments for constructor
     144    putDirect(exec->propertyNames().length, jsNumber(1), ReadOnly | DontDelete | DontEnum);
    164145}
    165146
    166147bool FunctionObjectImp::implementsConstruct() const
    167148{
    168   return true;
     149    return true;
    169150}
    170151
     
    172153JSObject* FunctionObjectImp::construct(ExecState* exec, const List& args, const Identifier& functionName, const UString& sourceURL, int lineNumber)
    173154{
    174   UString p("");
    175   UString body;
    176   int argsSize = args.size();
    177   if (argsSize == 0) {
    178     body = "";
    179   } else if (argsSize == 1) {
    180     body = args[0]->toString(exec);
    181   } else {
    182     p = args[0]->toString(exec);
    183     for (int k = 1; k < argsSize - 1; k++)
    184       p += "," + args[k]->toString(exec);
    185     body = args[argsSize-1]->toString(exec);
    186   }
    187 
    188   // parse the source code
    189   int sourceId;
    190   int errLine;
    191   UString errMsg;
    192   RefPtr<FunctionBodyNode> functionBody = parser().parse<FunctionBodyNode>(sourceURL, lineNumber, body.data(), body.size(), &sourceId, &errLine, &errMsg);
    193 
    194   // notify debugger that source has been parsed
    195   Debugger *dbg = exec->dynamicGlobalObject()->debugger();
    196   if (dbg) {
    197     // send empty sourceURL to indicate constructed code
    198     bool cont = dbg->sourceParsed(exec, sourceId, UString(), body, lineNumber, errLine, errMsg);
    199     if (!cont) {
    200       dbg->imp()->abort();
    201       return new JSObject();
    202     }
    203   }
    204 
    205   // no program node == syntax error - throw a syntax error
    206   if (!functionBody)
    207     // we can't return a Completion(Throw) here, so just set the exception
    208     // and return it
    209     return throwError(exec, SyntaxError, errMsg, errLine, sourceId, sourceURL);
    210 
    211   ScopeChain scopeChain;
    212   scopeChain.push(exec->lexicalGlobalObject());
    213 
    214   FunctionImp* fimp = new FunctionImp(exec, functionName, functionBody.get(), scopeChain);
     155    UString p("");
     156    UString body;
     157    int argsSize = args.size();
     158    if (argsSize == 0)
     159        body = "";
     160    else if (argsSize == 1)
     161        body = args[0]->toString(exec);
     162    else {
     163        p = args[0]->toString(exec);
     164        for (int k = 1; k < argsSize - 1; k++)
     165            p += "," + args[k]->toString(exec);
     166        body = args[argsSize - 1]->toString(exec);
     167    }
     168
     169    // parse the source code
     170    int sourceId;
     171    int errLine;
     172    UString errMsg;
     173    RefPtr<FunctionBodyNode> functionBody = parser().parse<FunctionBodyNode>(sourceURL, lineNumber, body.data(), body.size(), &sourceId, &errLine, &errMsg);
     174
     175    // notify debugger that source has been parsed
     176    Debugger* dbg = exec->dynamicGlobalObject()->debugger();
     177    if (dbg) {
     178        // send empty sourceURL to indicate constructed code
     179        bool cont = dbg->sourceParsed(exec, sourceId, UString(), body, lineNumber, errLine, errMsg);
     180        if (!cont) {
     181            dbg->imp()->abort();
     182            return new JSObject();
     183        }
     184    }
     185
     186    // No program node == syntax error - throw a syntax error
     187    if (!functionBody)
     188        // We can't return a Completion(Throw) here, so just set the exception
     189        // and return it
     190        return throwError(exec, SyntaxError, errMsg, errLine, sourceId, sourceURL);
     191
     192    ScopeChain scopeChain;
     193    scopeChain.push(exec->lexicalGlobalObject());
     194
     195    FunctionImp* fimp = new FunctionImp(exec, functionName, functionBody.get(), scopeChain);
     196
     197    // parse parameter list. throw syntax error on illegal identifiers
     198    int len = p.size();
     199    const UChar* c = p.data();
     200    int i = 0, params = 0;
     201    UString param;
     202    while (i < len) {
     203        while (*c == ' ' && i < len)
     204            c++, i++;
     205        if (Lexer::isIdentStart(c->uc)) {  // else error
     206            param = UString(c, 1);
     207            c++, i++;
     208            while (i < len && (Lexer::isIdentPart(c->uc))) {
     209                param += UString(c, 1);
     210                c++, i++;
     211            }
     212            while (i < len && *c == ' ')
     213                c++, i++;
     214            if (i == len) {
     215                functionBody->parameters().append(Identifier(param));
     216                params++;
     217                break;
     218            } else if (*c == ',') {
     219                functionBody->parameters().append(Identifier(param));
     220                params++;
     221                c++, i++;
     222                continue;
     223            } // else error
     224        }
     225        return throwError(exec, SyntaxError, "Syntax error in parameter list");
     226    }
    215227 
    216   // parse parameter list. throw syntax error on illegal identifiers
    217   int len = p.size();
    218   const UChar *c = p.data();
    219   int i = 0, params = 0;
    220   UString param;
    221   while (i < len) {
    222       while (*c == ' ' && i < len)
    223           c++, i++;
    224       if (Lexer::isIdentStart(c->uc)) {  // else error
    225           param = UString(c, 1);
    226           c++, i++;
    227           while (i < len && (Lexer::isIdentPart(c->uc))) {
    228               param += UString(c, 1);
    229               c++, i++;
    230           }
    231           while (i < len && *c == ' ')
    232               c++, i++;
    233           if (i == len) {
    234               functionBody->parameters().append(Identifier(param));
    235               params++;
    236               break;
    237           } else if (*c == ',') {
    238               functionBody->parameters().append(Identifier(param));
    239               params++;
    240               c++, i++;
    241               continue;
    242           } // else error
    243       }
    244       return throwError(exec, SyntaxError, "Syntax error in parameter list");
    245   }
    246  
    247   List consArgs;
    248 
    249   JSObject* objCons = exec->lexicalGlobalObject()->objectConstructor();
    250   JSObject* prototype = objCons->construct(exec, exec->emptyList());
    251   prototype->put(exec, exec->propertyNames().constructor, fimp, DontEnum|DontDelete|ReadOnly);
    252   fimp->put(exec, exec->propertyNames().prototype, prototype, Internal|DontDelete);
    253   return fimp;
     228    List consArgs;
     229
     230    JSObject* objCons = exec->lexicalGlobalObject()->objectConstructor();
     231    JSObject* prototype = objCons->construct(exec, exec->emptyList());
     232    prototype->put(exec, exec->propertyNames().constructor, fimp, DontEnum | DontDelete | ReadOnly);
     233    fimp->put(exec, exec->propertyNames().prototype, prototype, Internal | DontDelete);
     234    return fimp;
    254235}
    255236
     
    257238JSObject* FunctionObjectImp::construct(ExecState* exec, const List& args)
    258239{
    259   return construct(exec, args, "anonymous", UString(), 0);
     240    return construct(exec, args, "anonymous", UString(), 0);
    260241}
    261242
    262243// ECMA 15.3.1 The Function Constructor Called as a Function
    263 JSValue* FunctionObjectImp::callAsFunction(ExecState* exec, JSObject* /*thisObj*/, const List &args)
    264 {
    265   return construct(exec, args);
    266 }
     244JSValue* FunctionObjectImp::callAsFunction(ExecState* exec, JSObject*, const List& args)
     245{
     246    return construct(exec, args);
     247}
     248
     249} // namespace KJS
Note: See TracChangeset for help on using the changeset viewer.