JavaScriptCore/runtime/JSFunction.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  *  Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
       
     3  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
       
     4  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
       
     5  *  Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
       
     6  *  Copyright (C) 2007 Maks Orlovich
       
     7  *
       
     8  *  This library is free software; you can redistribute it and/or
       
     9  *  modify it under the terms of the GNU Library General Public
       
    10  *  License as published by the Free Software Foundation; either
       
    11  *  version 2 of the License, or (at your option) any later version.
       
    12  *
       
    13  *  This library is distributed in the hope that it will be useful,
       
    14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    16  *  Library General Public License for more details.
       
    17  *
       
    18  *  You should have received a copy of the GNU Library General Public License
       
    19  *  along with this library; see the file COPYING.LIB.  If not, write to
       
    20  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
       
    21  *  Boston, MA 02110-1301, USA.
       
    22  *
       
    23  */
       
    24 
       
    25 #include "config.h"
       
    26 #include "JSFunction.h"
       
    27 
       
    28 #include "CodeBlock.h"
       
    29 #include "CommonIdentifiers.h"
       
    30 #include "CallFrame.h"
       
    31 #include "ExceptionHelpers.h"
       
    32 #include "FunctionPrototype.h"
       
    33 #include "JSGlobalObject.h"
       
    34 #include "JSNotAnObject.h"
       
    35 #include "Interpreter.h"
       
    36 #include "ObjectPrototype.h"
       
    37 #include "Parser.h"
       
    38 #include "PropertyNameArray.h"
       
    39 #include "ScopeChainMark.h"
       
    40 
       
    41 using namespace WTF;
       
    42 using namespace Unicode;
       
    43 
       
    44 namespace JSC {
       
    45 #if ENABLE(JIT)
       
    46 EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec)
       
    47 {
       
    48     CodeBlock* codeBlock = exec->callerFrame()->codeBlock();
       
    49     unsigned vPCIndex = codeBlock->bytecodeOffset(exec, exec->returnPC());
       
    50     return throwVMError(exec, createNotAConstructorError(exec, exec->callee(), vPCIndex, codeBlock));
       
    51 }
       
    52 #endif
       
    53 
       
    54 ASSERT_CLASS_FITS_IN_CELL(JSFunction);
       
    55 
       
    56 const ClassInfo JSFunction::info = { "Function", 0, 0, 0 };
       
    57 
       
    58 bool JSFunction::isHostFunctionNonInline() const
       
    59 {
       
    60     return isHostFunction();
       
    61 }
       
    62 
       
    63 JSFunction::JSFunction(NonNullPassRefPtr<Structure> structure)
       
    64     : Base(structure)
       
    65     , m_executable(adoptRef(new VPtrHackExecutable()))
       
    66     , m_scopeChain(NoScopeChain())
       
    67 {
       
    68 }
       
    69 
       
    70 #if ENABLE(JIT)
       
    71 JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, int length, const Identifier& name, PassRefPtr<NativeExecutable> thunk)
       
    72     : Base(globalObject, structure)
       
    73     , m_executable(thunk)
       
    74     , m_scopeChain(globalObject->globalScopeChain())
       
    75 {
       
    76     putDirect(exec->globalData().propertyNames->name, jsString(exec, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum);
       
    77     putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum);
       
    78 }
       
    79 #endif
       
    80 
       
    81 JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, int length, const Identifier& name, NativeFunction func)
       
    82     : Base(globalObject, structure)
       
    83 #if ENABLE(JIT)
       
    84     , m_executable(exec->globalData().getHostFunction(func))
       
    85 #endif
       
    86     , m_scopeChain(globalObject->globalScopeChain())
       
    87 {
       
    88     putDirect(exec->globalData().propertyNames->name, jsString(exec, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum);
       
    89 #if ENABLE(JIT)
       
    90     putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum);
       
    91 #else
       
    92     UNUSED_PARAM(length);
       
    93     UNUSED_PARAM(func);
       
    94     ASSERT_NOT_REACHED();
       
    95 #endif
       
    96 }
       
    97 
       
    98 JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr<FunctionExecutable> executable, ScopeChainNode* scopeChainNode)
       
    99     : Base(scopeChainNode->globalObject, scopeChainNode->globalObject->functionStructure())
       
   100     , m_executable(executable)
       
   101     , m_scopeChain(scopeChainNode)
       
   102 {
       
   103     const Identifier& name = static_cast<FunctionExecutable*>(m_executable.get())->name();
       
   104     putDirect(exec->globalData().propertyNames->name, jsString(exec, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum);
       
   105 }
       
   106 
       
   107 JSFunction::~JSFunction()
       
   108 {
       
   109     ASSERT(vptr() == JSGlobalData::jsFunctionVPtr);
       
   110 
       
   111     // JIT code for other functions may have had calls linked directly to the code for this function; these links
       
   112     // are based on a check for the this pointer value for this JSFunction - which will no longer be valid once
       
   113     // this memory is freed and may be reused (potentially for another, different JSFunction).
       
   114     if (!isHostFunction()) {
       
   115 #if ENABLE(JIT_OPTIMIZE_CALL)
       
   116         ASSERT(m_executable);
       
   117         if (jsExecutable()->isGeneratedForCall())
       
   118             jsExecutable()->generatedBytecodeForCall().unlinkCallers();
       
   119         if (jsExecutable()->isGeneratedForConstruct())
       
   120             jsExecutable()->generatedBytecodeForConstruct().unlinkCallers();
       
   121 #endif
       
   122     }
       
   123 }
       
   124 
       
   125 const UString& JSFunction::name(ExecState* exec)
       
   126 {
       
   127     return asString(getDirect(exec->globalData().propertyNames->name))->tryGetValue();
       
   128 }
       
   129 
       
   130 const UString JSFunction::displayName(ExecState* exec)
       
   131 {
       
   132     JSValue displayName = getDirect(exec->globalData().propertyNames->displayName);
       
   133     
       
   134     if (displayName && isJSString(&exec->globalData(), displayName))
       
   135         return asString(displayName)->tryGetValue();
       
   136     
       
   137     return UString::null();
       
   138 }
       
   139 
       
   140 const UString JSFunction::calculatedDisplayName(ExecState* exec)
       
   141 {
       
   142     const UString explicitName = displayName(exec);
       
   143     
       
   144     if (!explicitName.isEmpty())
       
   145         return explicitName;
       
   146     
       
   147     return name(exec);
       
   148 }
       
   149 
       
   150 void JSFunction::markChildren(MarkStack& markStack)
       
   151 {
       
   152     Base::markChildren(markStack);
       
   153     if (!isHostFunction()) {
       
   154         jsExecutable()->markAggregate(markStack);
       
   155         scope().markAggregate(markStack);
       
   156     }
       
   157 }
       
   158 
       
   159 CallType JSFunction::getCallData(CallData& callData)
       
   160 {
       
   161 #if ENABLE(JIT)
       
   162     if (isHostFunction()) {
       
   163         callData.native.function = nativeFunction();
       
   164         return CallTypeHost;
       
   165     }
       
   166 #endif
       
   167     callData.js.functionExecutable = jsExecutable();
       
   168     callData.js.scopeChain = scope().node();
       
   169     return CallTypeJS;
       
   170 }
       
   171 
       
   172 JSValue JSFunction::argumentsGetter(ExecState* exec, JSValue slotBase, const Identifier&)
       
   173 {
       
   174     JSFunction* thisObj = asFunction(slotBase);
       
   175     ASSERT(!thisObj->isHostFunction());
       
   176     return exec->interpreter()->retrieveArguments(exec, thisObj);
       
   177 }
       
   178 
       
   179 JSValue JSFunction::callerGetter(ExecState* exec, JSValue slotBase, const Identifier&)
       
   180 {
       
   181     JSFunction* thisObj = asFunction(slotBase);
       
   182     ASSERT(!thisObj->isHostFunction());
       
   183     return exec->interpreter()->retrieveCaller(exec, thisObj);
       
   184 }
       
   185 
       
   186 JSValue JSFunction::lengthGetter(ExecState* exec, JSValue slotBase, const Identifier&)
       
   187 {
       
   188     JSFunction* thisObj = asFunction(slotBase);
       
   189     ASSERT(!thisObj->isHostFunction());
       
   190     return jsNumber(exec, thisObj->jsExecutable()->parameterCount());
       
   191 }
       
   192 
       
   193 bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
       
   194 {
       
   195     if (isHostFunction())
       
   196         return Base::getOwnPropertySlot(exec, propertyName, slot);
       
   197 
       
   198     if (propertyName == exec->propertyNames().prototype) {
       
   199         JSValue* location = getDirectLocation(propertyName);
       
   200 
       
   201         if (!location) {
       
   202             JSObject* prototype = new (exec) JSObject(scope().globalObject()->emptyObjectStructure());
       
   203             prototype->putDirect(exec->propertyNames().constructor, this, DontEnum);
       
   204             putDirect(exec->propertyNames().prototype, prototype, DontDelete);
       
   205             location = getDirectLocation(propertyName);
       
   206         }
       
   207 
       
   208         slot.setValueSlot(this, location, offsetForLocation(location));
       
   209     }
       
   210 
       
   211     if (propertyName == exec->propertyNames().arguments) {
       
   212         slot.setCacheableCustom(this, argumentsGetter);
       
   213         return true;
       
   214     }
       
   215 
       
   216     if (propertyName == exec->propertyNames().length) {
       
   217         slot.setCacheableCustom(this, lengthGetter);
       
   218         return true;
       
   219     }
       
   220 
       
   221     if (propertyName == exec->propertyNames().caller) {
       
   222         slot.setCacheableCustom(this, callerGetter);
       
   223         return true;
       
   224     }
       
   225 
       
   226     return Base::getOwnPropertySlot(exec, propertyName, slot);
       
   227 }
       
   228 
       
   229     bool JSFunction::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
       
   230     {
       
   231         if (isHostFunction())
       
   232             return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
       
   233         
       
   234         if (propertyName == exec->propertyNames().prototype) {
       
   235             PropertySlot slot;
       
   236             getOwnPropertySlot(exec, propertyName, slot);
       
   237             return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
       
   238         }
       
   239         
       
   240         if (propertyName == exec->propertyNames().arguments) {
       
   241             descriptor.setDescriptor(exec->interpreter()->retrieveArguments(exec, this), ReadOnly | DontEnum | DontDelete);
       
   242             return true;
       
   243         }
       
   244         
       
   245         if (propertyName == exec->propertyNames().length) {
       
   246             descriptor.setDescriptor(jsNumber(exec, jsExecutable()->parameterCount()), ReadOnly | DontEnum | DontDelete);
       
   247             return true;
       
   248         }
       
   249         
       
   250         if (propertyName == exec->propertyNames().caller) {
       
   251             descriptor.setDescriptor(exec->interpreter()->retrieveCaller(exec, this), ReadOnly | DontEnum | DontDelete);
       
   252             return true;
       
   253         }
       
   254         
       
   255         return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);
       
   256     }
       
   257     
       
   258 void JSFunction::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
       
   259 {
       
   260     if (!isHostFunction() && (mode == IncludeDontEnumProperties)) {
       
   261         propertyNames.add(exec->propertyNames().arguments);
       
   262         propertyNames.add(exec->propertyNames().callee);
       
   263         propertyNames.add(exec->propertyNames().caller);
       
   264         propertyNames.add(exec->propertyNames().length);
       
   265     }
       
   266     Base::getOwnPropertyNames(exec, propertyNames, mode);
       
   267 }
       
   268 
       
   269 void JSFunction::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
       
   270 {
       
   271     if (isHostFunction()) {
       
   272         Base::put(exec, propertyName, value, slot);
       
   273         return;
       
   274     }
       
   275     if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
       
   276         return;
       
   277     Base::put(exec, propertyName, value, slot);
       
   278 }
       
   279 
       
   280 bool JSFunction::deleteProperty(ExecState* exec, const Identifier& propertyName)
       
   281 {
       
   282     if (isHostFunction())
       
   283         return Base::deleteProperty(exec, propertyName);
       
   284     if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
       
   285         return false;
       
   286     return Base::deleteProperty(exec, propertyName);
       
   287 }
       
   288 
       
   289 // ECMA 13.2.2 [[Construct]]
       
   290 ConstructType JSFunction::getConstructData(ConstructData& constructData)
       
   291 {
       
   292     if (isHostFunction())
       
   293         return ConstructTypeNone;
       
   294     constructData.js.functionExecutable = jsExecutable();
       
   295     constructData.js.scopeChain = scope().node();
       
   296     return ConstructTypeJS;
       
   297 }
       
   298 
       
   299 } // namespace JSC