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 
   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. 
  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. 
  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. 
  26 #include "JSFunction.h" 
  28 #include "CodeBlock.h" 
  29 #include "CommonIdentifiers.h" 
  30 #include "CallFrame.h" 
  31 #include "FunctionPrototype.h" 
  32 #include "JSGlobalObject.h" 
  33 #include "Interpreter.h" 
  34 #include "ObjectPrototype.h" 
  36 #include "PropertyNameArray.h" 
  37 #include "ScopeChainMark.h" 
  40 using namespace Unicode
; 
  44 ASSERT_CLASS_FITS_IN_CELL(JSFunction
); 
  46 const ClassInfo 
JSFunction::info 
= { "Function", &InternalFunction::info
, 0, 0 }; 
  48 bool JSFunction::isHostFunctionNonInline() const 
  50     return isHostFunction(); 
  53 JSFunction::JSFunction(NonNullPassRefPtr
<Structure
> structure
) 
  55     , m_executable(adoptRef(new VPtrHackExecutable())) 
  59 JSFunction::JSFunction(ExecState
* exec
, NonNullPassRefPtr
<Structure
> structure
, int length
, const Identifier
& name
, NativeFunction func
) 
  60     : Base(&exec
->globalData(), structure
, name
) 
  62     , m_executable(adoptRef(new NativeExecutable(exec
))) 
  66     setNativeFunction(func
); 
  67     putDirect(exec
->propertyNames().length
, jsNumber(exec
, length
), DontDelete 
| ReadOnly 
| DontEnum
); 
  75 JSFunction::JSFunction(ExecState
* exec
, NonNullPassRefPtr
<FunctionExecutable
> executable
, ScopeChainNode
* scopeChainNode
) 
  76     : Base(&exec
->globalData(), exec
->lexicalGlobalObject()->functionStructure(), executable
->name()) 
  77     , m_executable(executable
) 
  79     setScopeChain(scopeChainNode
); 
  82 JSFunction::~JSFunction() 
  84     ASSERT(vptr() == JSGlobalData::jsFunctionVPtr
); 
  86     // JIT code for other functions may have had calls linked directly to the code for this function; these links 
  87     // are based on a check for the this pointer value for this JSFunction - which will no longer be valid once 
  88     // this memory is freed and may be reused (potentially for another, different JSFunction). 
  89     if (!isHostFunction()) { 
  90 #if ENABLE(JIT_OPTIMIZE_CALL) 
  92         if (jsExecutable()->isGenerated()) 
  93             jsExecutable()->generatedBytecode().unlinkCallers(); 
  95         scopeChain().~ScopeChain(); // FIXME: Don't we need to do this in the interpreter too? 
  99 void JSFunction::markChildren(MarkStack
& markStack
) 
 101     Base::markChildren(markStack
); 
 102     if (!isHostFunction()) { 
 103         jsExecutable()->markAggregate(markStack
); 
 104         scopeChain().markAggregate(markStack
); 
 108 CallType 
JSFunction::getCallData(CallData
& callData
) 
 110     if (isHostFunction()) { 
 111         callData
.native
.function 
= nativeFunction(); 
 114     callData
.js
.functionExecutable 
= jsExecutable(); 
 115     callData
.js
.scopeChain 
= scopeChain().node(); 
 119 JSValue 
JSFunction::call(ExecState
* exec
, JSValue thisValue
, const ArgList
& args
) 
 121     ASSERT(!isHostFunction()); 
 122     return exec
->interpreter()->execute(jsExecutable(), exec
, this, thisValue
.toThisObject(exec
), args
, scopeChain().node(), exec
->exceptionSlot()); 
 125 JSValue 
JSFunction::argumentsGetter(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
) 
 127     JSFunction
* thisObj 
= asFunction(slot
.slotBase()); 
 128     ASSERT(!thisObj
->isHostFunction()); 
 129     return exec
->interpreter()->retrieveArguments(exec
, thisObj
); 
 132 JSValue 
JSFunction::callerGetter(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
) 
 134     JSFunction
* thisObj 
= asFunction(slot
.slotBase()); 
 135     ASSERT(!thisObj
->isHostFunction()); 
 136     return exec
->interpreter()->retrieveCaller(exec
, thisObj
); 
 139 JSValue 
JSFunction::lengthGetter(ExecState
* exec
, const Identifier
&, const PropertySlot
& slot
) 
 141     JSFunction
* thisObj 
= asFunction(slot
.slotBase()); 
 142     ASSERT(!thisObj
->isHostFunction()); 
 143     return jsNumber(exec
, thisObj
->jsExecutable()->parameterCount()); 
 146 bool JSFunction::getOwnPropertySlot(ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
& slot
) 
 148     if (isHostFunction()) 
 149         return Base::getOwnPropertySlot(exec
, propertyName
, slot
); 
 151     if (propertyName 
== exec
->propertyNames().prototype
) { 
 152         JSValue
* location 
= getDirectLocation(propertyName
); 
 155             JSObject
* prototype 
= new (exec
) JSObject(scopeChain().globalObject()->emptyObjectStructure()); 
 156             prototype
->putDirect(exec
->propertyNames().constructor
, this, DontEnum
); 
 157             putDirect(exec
->propertyNames().prototype
, prototype
, DontDelete
); 
 158             location 
= getDirectLocation(propertyName
); 
 161         slot
.setValueSlot(this, location
, offsetForLocation(location
)); 
 164     if (propertyName 
== exec
->propertyNames().arguments
) { 
 165         slot
.setCustom(this, argumentsGetter
); 
 169     if (propertyName 
== exec
->propertyNames().length
) { 
 170         slot
.setCustom(this, lengthGetter
); 
 174     if (propertyName 
== exec
->propertyNames().caller
) { 
 175         slot
.setCustom(this, callerGetter
); 
 179     return Base::getOwnPropertySlot(exec
, propertyName
, slot
); 
 182     bool JSFunction::getOwnPropertyDescriptor(ExecState
* exec
, const Identifier
& propertyName
, PropertyDescriptor
& descriptor
) 
 184         if (isHostFunction()) 
 185             return Base::getOwnPropertyDescriptor(exec
, propertyName
, descriptor
); 
 187         if (propertyName 
== exec
->propertyNames().prototype
) { 
 189             getOwnPropertySlot(exec
, propertyName
, slot
); 
 190             return Base::getOwnPropertyDescriptor(exec
, propertyName
, descriptor
); 
 193         if (propertyName 
== exec
->propertyNames().arguments
) { 
 194             descriptor
.setDescriptor(exec
->interpreter()->retrieveArguments(exec
, this), ReadOnly 
| DontEnum 
| DontDelete
); 
 198         if (propertyName 
== exec
->propertyNames().length
) { 
 199             descriptor
.setDescriptor(jsNumber(exec
, jsExecutable()->parameterCount()), ReadOnly 
| DontEnum 
| DontDelete
); 
 203         if (propertyName 
== exec
->propertyNames().caller
) { 
 204             descriptor
.setDescriptor(exec
->interpreter()->retrieveCaller(exec
, this), ReadOnly 
| DontEnum 
| DontDelete
); 
 208         return Base::getOwnPropertyDescriptor(exec
, propertyName
, descriptor
); 
 211 void JSFunction::getOwnPropertyNames(ExecState
* exec
, PropertyNameArray
& propertyNames
, EnumerationMode mode
) 
 213     if (!isHostFunction() && (mode 
== IncludeDontEnumProperties
)) { 
 214         propertyNames
.add(exec
->propertyNames().arguments
); 
 215         propertyNames
.add(exec
->propertyNames().callee
); 
 216         propertyNames
.add(exec
->propertyNames().caller
); 
 217         propertyNames
.add(exec
->propertyNames().length
); 
 219     Base::getOwnPropertyNames(exec
, propertyNames
, mode
); 
 222 void JSFunction::put(ExecState
* exec
, const Identifier
& propertyName
, JSValue value
, PutPropertySlot
& slot
) 
 224     if (isHostFunction()) { 
 225         Base::put(exec
, propertyName
, value
, slot
); 
 228     if (propertyName 
== exec
->propertyNames().arguments 
|| propertyName 
== exec
->propertyNames().length
) 
 230     Base::put(exec
, propertyName
, value
, slot
); 
 233 bool JSFunction::deleteProperty(ExecState
* exec
, const Identifier
& propertyName
) 
 235     if (isHostFunction()) 
 236         return Base::deleteProperty(exec
, propertyName
); 
 237     if (propertyName 
== exec
->propertyNames().arguments 
|| propertyName 
== exec
->propertyNames().length
) 
 239     return Base::deleteProperty(exec
, propertyName
); 
 242 // ECMA 13.2.2 [[Construct]] 
 243 ConstructType 
JSFunction::getConstructData(ConstructData
& constructData
) 
 245     if (isHostFunction()) 
 246         return ConstructTypeNone
; 
 247     constructData
.js
.functionExecutable 
= jsExecutable(); 
 248     constructData
.js
.scopeChain 
= scopeChain().node(); 
 249     return ConstructTypeJS
; 
 252 JSObject
* JSFunction::construct(ExecState
* exec
, const ArgList
& args
) 
 254     ASSERT(!isHostFunction()); 
 255     Structure
* structure
; 
 256     JSValue prototype 
= get(exec
, exec
->propertyNames().prototype
); 
 257     if (prototype
.isObject()) 
 258         structure 
= asObject(prototype
)->inheritorID(); 
 260         structure 
= exec
->lexicalGlobalObject()->emptyObjectStructure(); 
 261     JSObject
* thisObj 
= new (exec
) JSObject(structure
); 
 263     JSValue result 
= exec
->interpreter()->execute(jsExecutable(), exec
, this, thisObj
, args
, scopeChain().node(), exec
->exceptionSlot()); 
 264     if (exec
->hadException() || !result
.isObject()) 
 266     return asObject(result
);