Home | History | Annotate | Download | only in runtime
      1 /*
      2  *  Copyright (C) 1999-2001 Harri Porten (porten (at) kde.org)
      3  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
      4  *
      5  *  This library is free software; you can redistribute it and/or
      6  *  modify it under the terms of the GNU Lesser General Public
      7  *  License as published by the Free Software Foundation; either
      8  *  version 2 of the License, or (at your option) any later version.
      9  *
     10  *  This library is distributed in the hope that it will be useful,
     11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  *  Lesser General Public License for more details.
     14  *
     15  *  You should have received a copy of the GNU Lesser General Public
     16  *  License along with this library; if not, write to the Free Software
     17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     18  *
     19  */
     20 
     21 #include "config.h"
     22 #include "FunctionPrototype.h"
     23 
     24 #include "Arguments.h"
     25 #include "JSArray.h"
     26 #include "JSFunction.h"
     27 #include "JSString.h"
     28 #include "JSStringBuilder.h"
     29 #include "Interpreter.h"
     30 #include "Lexer.h"
     31 
     32 namespace JSC {
     33 
     34 ASSERT_CLASS_FITS_IN_CELL(FunctionPrototype);
     35 
     36 static EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState*);
     37 static EncodedJSValue JSC_HOST_CALL functionProtoFuncApply(ExecState*);
     38 static EncodedJSValue JSC_HOST_CALL functionProtoFuncCall(ExecState*);
     39 
     40 FunctionPrototype::FunctionPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
     41     : InternalFunction(&exec->globalData(), globalObject, structure, exec->propertyNames().nullIdentifier)
     42 {
     43     putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
     44 }
     45 
     46 void FunctionPrototype::addFunctionProperties(ExecState* exec, JSGlobalObject* globalObject, Structure* functionStructure, JSFunction** callFunction, JSFunction** applyFunction)
     47 {
     48     putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().toString, functionProtoFuncToString), DontEnum);
     49     *applyFunction = new (exec) JSFunction(exec, globalObject, functionStructure, 2, exec->propertyNames().apply, functionProtoFuncApply);
     50     putDirectFunctionWithoutTransition(exec, *applyFunction, DontEnum);
     51     *callFunction = new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().call, functionProtoFuncCall);
     52     putDirectFunctionWithoutTransition(exec, *callFunction, DontEnum);
     53 }
     54 
     55 static EncodedJSValue JSC_HOST_CALL callFunctionPrototype(ExecState*)
     56 {
     57     return JSValue::encode(jsUndefined());
     58 }
     59 
     60 // ECMA 15.3.4
     61 CallType FunctionPrototype::getCallData(CallData& callData)
     62 {
     63     callData.native.function = callFunctionPrototype;
     64     return CallTypeHost;
     65 }
     66 
     67 // Functions
     68 
     69 // Compatibility hack for the Optimost JavaScript library. (See <rdar://problem/6595040>.)
     70 static inline void insertSemicolonIfNeeded(UString& functionBody)
     71 {
     72     ASSERT(functionBody[0] == '{');
     73     ASSERT(functionBody[functionBody.length() - 1] == '}');
     74 
     75     for (size_t i = functionBody.length() - 2; i > 0; --i) {
     76         UChar ch = functionBody[i];
     77         if (!Lexer::isWhiteSpace(ch) && !Lexer::isLineTerminator(ch)) {
     78             if (ch != ';' && ch != '}')
     79                 functionBody = makeUString(functionBody.substringSharingImpl(0, i + 1), ";", functionBody.substringSharingImpl(i + 1, functionBody.length() - (i + 1)));
     80             return;
     81         }
     82     }
     83 }
     84 
     85 EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec)
     86 {
     87     JSValue thisValue = exec->hostThisValue();
     88     if (thisValue.inherits(&JSFunction::s_info)) {
     89         JSFunction* function = asFunction(thisValue);
     90         if (function->isHostFunction())
     91             return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n    [native code]\n}"));
     92         FunctionExecutable* executable = function->jsExecutable();
     93         UString sourceString = executable->source().toString();
     94         insertSemicolonIfNeeded(sourceString);
     95         return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "(", executable->paramString(), ") ", sourceString));
     96     }
     97 
     98     if (thisValue.inherits(&InternalFunction::s_info)) {
     99         InternalFunction* function = asInternalFunction(thisValue);
    100         return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n    [native code]\n}"));
    101     }
    102 
    103     return throwVMTypeError(exec);
    104 }
    105 
    106 EncodedJSValue JSC_HOST_CALL functionProtoFuncApply(ExecState* exec)
    107 {
    108     JSValue thisValue = exec->hostThisValue();
    109     CallData callData;
    110     CallType callType = getCallData(thisValue, callData);
    111     if (callType == CallTypeNone)
    112         return throwVMTypeError(exec);
    113 
    114     JSValue array = exec->argument(1);
    115 
    116     MarkedArgumentBuffer applyArgs;
    117     if (!array.isUndefinedOrNull()) {
    118         if (!array.isObject())
    119             return throwVMTypeError(exec);
    120         if (asObject(array)->classInfo() == &Arguments::s_info)
    121             asArguments(array)->fillArgList(exec, applyArgs);
    122         else if (isJSArray(&exec->globalData(), array))
    123             asArray(array)->fillArgList(exec, applyArgs);
    124         else if (asObject(array)->inherits(&JSArray::s_info)) {
    125             unsigned length = asArray(array)->get(exec, exec->propertyNames().length).toUInt32(exec);
    126             for (unsigned i = 0; i < length; ++i)
    127                 applyArgs.append(asArray(array)->get(exec, i));
    128         } else
    129             return throwVMTypeError(exec);
    130     }
    131 
    132     return JSValue::encode(call(exec, thisValue, callType, callData, exec->argument(0), applyArgs));
    133 }
    134 
    135 EncodedJSValue JSC_HOST_CALL functionProtoFuncCall(ExecState* exec)
    136 {
    137     JSValue thisValue = exec->hostThisValue();
    138     CallData callData;
    139     CallType callType = getCallData(thisValue, callData);
    140     if (callType == CallTypeNone)
    141         return throwVMTypeError(exec);
    142 
    143     ArgList args(exec);
    144     ArgList callArgs;
    145     args.getSlice(1, callArgs);
    146     return JSValue::encode(call(exec, thisValue, callType, callData, exec->argument(0), callArgs));
    147 }
    148 
    149 } // namespace JSC
    150