Ignore:
Timestamp:
Oct 24, 2007, 11:38:35 PM (18 years ago)
Author:
eseidel
Message:

2007-10-24 Eric Seidel <[email protected]>

Reviewed by Maciej.


Add a JSGlobalObject class and remove the InterpreterMap
http://bugs.webkit.org/show_bug.cgi?id=15681


This required making JSCallbackObject a template class to allow for
JSGlobalObjects with JSCallbackObject functionality.


SunSpider claims this was a 0.5% speedup.

  • API/JSCallbackObject.cpp: (KJS::):
  • API/JSCallbackObject.h:
  • API/JSCallbackObjectFunctions.h: Copied from API/JSCallbackObject.cpp. (KJS::::JSCallbackObject): (KJS::::init): (KJS::::~JSCallbackObject): (KJS::::initializeIfNeeded): (KJS::::className): (KJS::::getOwnPropertySlot): (KJS::::put): (KJS::::deleteProperty): (KJS::::implementsConstruct): (KJS::::construct): (KJS::::implementsHasInstance): (KJS::::hasInstance): (KJS::::implementsCall): (KJS::::callAsFunction): (KJS::::getPropertyNames): (KJS::::toNumber): (KJS::::toString): (KJS::::setPrivate): (KJS::::getPrivate): (KJS::::inherits): (KJS::::cachedValueGetter): (KJS::::staticValueGetter): (KJS::::staticFunctionGetter): (KJS::::callbackGetter):
  • API/JSClassRef.cpp: (OpaqueJSClass::prototype):
  • API/JSContextRef.cpp: (JSGlobalContextCreate):
  • API/JSObjectRef.cpp: (JSObjectMake): (JSObjectGetPrivate): (JSObjectSetPrivate):
  • API/JSValueRef.cpp: (JSValueIsObjectOfClass):
  • JavaScriptCore.exp:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bindings/c/c_utility.cpp: (KJS::Bindings::convertValueToNPVariant):
  • bindings/jni/jni_jsobject.cpp:
  • bindings/objc/objc_utility.mm: (KJS::Bindings::convertValueToObjcValue):
  • kjs/Context.cpp: (KJS::Context::Context):
  • kjs/ExecState.cpp: (KJS::ExecState::lexicalInterpreter):
  • kjs/JSGlobalObject.h: Added. (KJS::JSGlobalObject::JSGlobalObject): (KJS::JSGlobalObject::isGlobalObject): (KJS::JSGlobalObject::interpreter): (KJS::JSGlobalObject::setInterpreter):
  • kjs/array_instance.cpp:
  • kjs/context.h:
  • kjs/function.cpp: (KJS::FunctionImp::callAsFunction): (KJS::GlobalFuncImp::callAsFunction):
  • kjs/interpreter.cpp: (KJS::Interpreter::Interpreter): (KJS::Interpreter::init): (KJS::Interpreter::~Interpreter): (KJS::Interpreter::globalObject): (KJS::Interpreter::initGlobalObject): (KJS::Interpreter::evaluate):
  • kjs/interpreter.h:
  • kjs/lookup.h: (KJS::cacheGlobalObject):
  • kjs/object.h: (KJS::JSObject::isGlobalObject):
  • kjs/testkjs.cpp:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/API/JSCallbackObject.cpp

    r25258 r27022  
    22/*
    33 * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
     4 * Copyright (C) 2007 Eric Seidel <[email protected]>
    45 *
    56 * Redistribution and use in source and binary forms, with or without
     
    2526 */
    2627
    27 #include <wtf/Platform.h>
    2828#include "JSCallbackObject.h"
    29 
    30 #include "APICast.h"
    31 #include "JSCallbackFunction.h"
    32 #include "JSClassRef.h"
    33 #include "JSObjectRef.h"
    34 #include "JSStringRef.h"
    35 #include "PropertyNameArray.h"
    36 #include "internal.h"
    37 #include <wtf/Vector.h>
    3829
    3930namespace KJS {
    4031
    41 const ClassInfo JSCallbackObject::info = { "CallbackObject", 0, 0, 0 };
    42 
    43 JSCallbackObject::JSCallbackObject(ExecState* exec, JSClassRef jsClass, JSValue* prototype, void* data)
    44     : JSObject(prototype)
    45     , m_class(0)
    46     , m_isInitialized(false)
    47 {
    48     init(exec, jsClass, data);
    49 }
    50 
    51 void JSCallbackObject::init(ExecState* exec, JSClassRef jsClass, void* data)
    52 {
    53     m_privateData = data;
    54     JSClassRef oldClass = m_class;
    55     m_class = JSClassRetain(jsClass);
    56     if (oldClass)
    57         JSClassRelease(oldClass);
    58 
    59     if (!exec)
    60         return;
    61 
    62     Vector<JSObjectInitializeCallback, 16> initRoutines;
    63     do {
    64         if (JSObjectInitializeCallback initialize = jsClass->initialize)
    65             initRoutines.append(initialize);
    66     } while ((jsClass = jsClass->parentClass));
    67    
    68     // initialize from base to derived
    69     for (int i = static_cast<int>(initRoutines.size()) - 1; i >= 0; i--) {
    70         JSLock::DropAllLocks dropAllLocks;
    71         JSObjectInitializeCallback initialize = initRoutines[i];
    72         initialize(toRef(exec), toRef(this));
    73     }
    74     m_isInitialized = true;
    75 }
    76 
    77 JSCallbackObject::~JSCallbackObject()
    78 {
    79     JSObjectRef thisRef = toRef(this);
    80    
    81     for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
    82         if (JSObjectFinalizeCallback finalize = jsClass->finalize) {
    83             finalize(thisRef);
    84         }
    85    
    86     JSClassRelease(m_class);
    87 }
    88 
    89 void JSCallbackObject::initializeIfNeeded(ExecState* exec)
    90 {
    91     if (m_isInitialized)
    92         return;
    93     init(exec, m_class, m_privateData);
    94 }
    95 
    96 UString JSCallbackObject::className() const
    97 {
    98     if (!m_class->className.isNull())
    99         return m_class->className;
    100    
    101     return JSObject::className();
    102 }
    103 
    104 bool JSCallbackObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
    105 {
    106     JSContextRef ctx = toRef(exec);
    107     JSObjectRef thisRef = toRef(this);
    108     JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
    109 
    110     for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
    111         // optional optimization to bypass getProperty in cases when we only need to know if the property exists
    112         if (JSObjectHasPropertyCallback hasProperty = jsClass->hasProperty) {
    113             JSLock::DropAllLocks dropAllLocks;
    114             if (hasProperty(ctx, thisRef, propertyNameRef)) {
    115                 slot.setCustom(this, callbackGetter);
    116                 return true;
    117             }
    118         } else if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) {
    119             JSLock::DropAllLocks dropAllLocks;
    120             if (JSValueRef value = getProperty(ctx, thisRef, propertyNameRef, toRef(exec->exceptionSlot()))) {
    121                 // cache the value so we don't have to compute it again
    122                 // FIXME: This violates the PropertySlot design a little bit.
    123                 // We should either use this optimization everywhere, or nowhere.
    124                 slot.setCustom(reinterpret_cast<JSObject*>(toJS(value)), cachedValueGetter);
    125                 return true;
    126             }
    127         }
    128 
    129         if (OpaqueJSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
    130             if (staticValues->contains(propertyName.ustring().rep())) {
    131                 slot.setCustom(this, staticValueGetter);
    132                 return true;
    133             }
    134         }
    135        
    136         if (OpaqueJSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
    137             if (staticFunctions->contains(propertyName.ustring().rep())) {
    138                 slot.setCustom(this, staticFunctionGetter);
    139                 return true;
    140             }
    141         }
    142     }
    143 
    144     return JSObject::getOwnPropertySlot(exec, propertyName, slot);
    145 }
    146 
    147 bool JSCallbackObject::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
    148 {
    149     return getOwnPropertySlot(exec, Identifier::from(propertyName), slot);
    150 }
    151 
    152 void JSCallbackObject::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
    153 {
    154     JSContextRef ctx = toRef(exec);
    155     JSObjectRef thisRef = toRef(this);
    156     JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
    157     JSValueRef valueRef = toRef(value);
    158 
    159     for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
    160         if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) {
    161             JSLock::DropAllLocks dropAllLocks;
    162             if (setProperty(ctx, thisRef, propertyNameRef, valueRef, toRef(exec->exceptionSlot())))
    163                 return;
    164         }
    165    
    166         if (OpaqueJSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
    167             if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
    168                 if (entry->attributes & kJSPropertyAttributeReadOnly)
    169                     return;
    170                 if (JSObjectSetPropertyCallback setProperty = entry->setProperty) {
    171                     JSLock::DropAllLocks dropAllLocks;
    172                     if (setProperty(ctx, thisRef, propertyNameRef, valueRef, toRef(exec->exceptionSlot())))
    173                         return;
    174                 } else
    175                     throwError(exec, ReferenceError, "Attempt to set a property that is not settable.");
    176             }
    177         }
    178        
    179         if (OpaqueJSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
    180             if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
    181                 if (entry->attributes & kJSPropertyAttributeReadOnly)
    182                     return;
    183                 putDirect(propertyName, value, attr); // put as override property
    184                 return;
    185             }
    186         }
    187     }
    188 
    189     return JSObject::put(exec, propertyName, value, attr);
    190 }
    191 
    192 void JSCallbackObject::put(ExecState* exec, unsigned propertyName, JSValue* value, int attr)
    193 {
    194     return put(exec, Identifier::from(propertyName), value, attr);
    195 }
    196 
    197 bool JSCallbackObject::deleteProperty(ExecState* exec, const Identifier& propertyName)
    198 {
    199     JSContextRef ctx = toRef(exec);
    200     JSObjectRef thisRef = toRef(this);
    201     JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
    202    
    203     for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
    204         if (JSObjectDeletePropertyCallback deleteProperty = jsClass->deleteProperty) {
    205             JSLock::DropAllLocks dropAllLocks;
    206             if (deleteProperty(ctx, thisRef, propertyNameRef, toRef(exec->exceptionSlot())))
    207                 return true;
    208         }
    209 
    210         if (OpaqueJSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
    211             if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep())) {
    212                 if (entry->attributes & kJSPropertyAttributeDontDelete)
    213                     return false;
    214                 return true;
    215             }
    216         }
    217        
    218         if (OpaqueJSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
    219             if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
    220                 if (entry->attributes & kJSPropertyAttributeDontDelete)
    221                     return false;
    222                 return true;
    223             }
    224         }
    225     }
    226 
    227     return JSObject::deleteProperty(exec, propertyName);
    228 }
    229 
    230 bool JSCallbackObject::deleteProperty(ExecState* exec, unsigned propertyName)
    231 {
    232     return deleteProperty(exec, Identifier::from(propertyName));
    233 }
    234 
    235 bool JSCallbackObject::implementsConstruct() const
    236 {
    237     for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
    238         if (jsClass->callAsConstructor)
    239             return true;
    240 
    241     return false;
    242 }
    243 
    244 JSObject* JSCallbackObject::construct(ExecState* exec, const List& args)
    245 {
    246     JSContextRef execRef = toRef(exec);
    247     JSObjectRef thisRef = toRef(this);
    248    
    249     for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
    250         if (JSObjectCallAsConstructorCallback callAsConstructor = jsClass->callAsConstructor) {
    251             int argumentCount = static_cast<int>(args.size());
    252             Vector<JSValueRef, 16> arguments(argumentCount);
    253             for (int i = 0; i < argumentCount; i++)
    254                 arguments[i] = toRef(args[i]);
    255             JSLock::DropAllLocks dropAllLocks;
    256             return toJS(callAsConstructor(execRef, thisRef, argumentCount, arguments.data(), toRef(exec->exceptionSlot())));
    257         }
    258     }
    259    
    260     ASSERT(0); // implementsConstruct should prevent us from reaching here
    261     return 0;
    262 }
    263 
    264 bool JSCallbackObject::implementsHasInstance() const
    265 {
    266     for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
    267         if (jsClass->hasInstance)
    268             return true;
    269 
    270     return false;
    271 }
    272 
    273 bool JSCallbackObject::hasInstance(ExecState *exec, JSValue *value)
    274 {
    275     JSContextRef execRef = toRef(exec);
    276     JSObjectRef thisRef = toRef(this);
    277 
    278     for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
    279         if (JSObjectHasInstanceCallback hasInstance = jsClass->hasInstance) {
    280             JSLock::DropAllLocks dropAllLocks;
    281             return hasInstance(execRef, thisRef, toRef(value), toRef(exec->exceptionSlot()));
    282         }
    283 
    284     ASSERT(0); // implementsHasInstance should prevent us from reaching here
    285     return 0;
    286 }
    287 
    288 
    289 bool JSCallbackObject::implementsCall() const
    290 {
    291     for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
    292         if (jsClass->callAsFunction)
    293             return true;
    294    
    295     return false;
    296 }
    297 
    298 JSValue* JSCallbackObject::callAsFunction(ExecState* exec, JSObject* thisObj, const List &args)
    299 {
    300     JSContextRef execRef = toRef(exec);
    301     JSObjectRef thisRef = toRef(this);
    302     JSObjectRef thisObjRef = toRef(thisObj);
    303 
    304     for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
    305         if (JSObjectCallAsFunctionCallback callAsFunction = jsClass->callAsFunction) {
    306             int argumentCount = static_cast<int>(args.size());
    307             Vector<JSValueRef, 16> arguments(argumentCount);
    308             for (int i = 0; i < argumentCount; i++)
    309                 arguments[i] = toRef(args[i]);
    310             JSLock::DropAllLocks dropAllLocks;
    311             return toJS(callAsFunction(execRef, thisRef, thisObjRef, argumentCount, arguments.data(), toRef(exec->exceptionSlot())));
    312         }
    313     }
    314 
    315     ASSERT(0); // implementsCall should prevent us from reaching here
    316     return 0;
    317 }
    318 
    319 void JSCallbackObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
    320 {
    321     JSContextRef execRef = toRef(exec);
    322     JSObjectRef thisRef = toRef(this);
    323 
    324     for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
    325         if (JSObjectGetPropertyNamesCallback getPropertyNames = jsClass->getPropertyNames) {
    326             JSLock::DropAllLocks dropAllLocks;
    327             getPropertyNames(execRef, thisRef, toRef(&propertyNames));
    328         }
    329 
    330         if (OpaqueJSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
    331             typedef OpaqueJSClass::StaticValuesTable::const_iterator iterator;
    332             iterator end = staticValues->end();
    333             for (iterator it = staticValues->begin(); it != end; ++it) {
    334                 UString::Rep* name = it->first.get();
    335                 StaticValueEntry* entry = it->second;
    336                 if (entry->getProperty && !(entry->attributes & kJSPropertyAttributeDontEnum))
    337                     propertyNames.add(Identifier(name));
    338             }
    339         }
    340 
    341         if (OpaqueJSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
    342             typedef OpaqueJSClass::StaticFunctionsTable::const_iterator iterator;
    343             iterator end = staticFunctions->end();
    344             for (iterator it = staticFunctions->begin(); it != end; ++it) {
    345                 UString::Rep* name = it->first.get();
    346                 StaticFunctionEntry* entry = it->second;
    347                 if (!(entry->attributes & kJSPropertyAttributeDontEnum))
    348                     propertyNames.add(Identifier(name));
    349             }
    350         }
    351     }
    352 
    353     JSObject::getPropertyNames(exec, propertyNames);
    354 }
    355 
    356 double JSCallbackObject::toNumber(ExecState* exec) const
    357 {
    358     JSContextRef ctx = toRef(exec);
    359     JSObjectRef thisRef = toRef(this);
    360 
    361     for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
    362         if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) {
    363             JSLock::DropAllLocks dropAllLocks;
    364             if (JSValueRef value = convertToType(ctx, thisRef, kJSTypeNumber, toRef(exec->exceptionSlot())))
    365                 return toJS(value)->getNumber();
    366         }
    367 
    368     return JSObject::toNumber(exec);
    369 }
    370 
    371 UString JSCallbackObject::toString(ExecState* exec) const
    372 {
    373     JSContextRef ctx = toRef(exec);
    374     JSObjectRef thisRef = toRef(this);
    375 
    376     for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
    377         if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) {
    378             JSLock::DropAllLocks dropAllLocks;
    379             if (JSValueRef value = convertToType(ctx, thisRef, kJSTypeString, toRef(exec->exceptionSlot())))
    380                 return toJS(value)->getString();
    381         }
    382 
    383     return JSObject::toString(exec);
    384 }
    385 
    386 void JSCallbackObject::setPrivate(void* data)
    387 {
    388     m_privateData = data;
    389 }
    390 
    391 void* JSCallbackObject::getPrivate()
    392 {
    393     return m_privateData;
    394 }
    395 
    396 bool JSCallbackObject::inherits(JSClassRef c) const
    397 {
    398     for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
    399         if (jsClass == c)
    400             return true;
    401 
    402     return false;
    403 }
    404 
    405 JSValue* JSCallbackObject::cachedValueGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot)
    406 {
    407     JSValue* v = slot.slotBase();
    408     ASSERT(v);
    409     return v;
    410 }
    411 
    412 JSValue* JSCallbackObject::staticValueGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
    413 {
    414     ASSERT(slot.slotBase()->inherits(&JSCallbackObject::info));
    415     JSCallbackObject* thisObj = static_cast<JSCallbackObject*>(slot.slotBase());
    416 
    417     JSObjectRef thisRef = toRef(thisObj);
    418     JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
    419 
    420     for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parentClass)
    421         if (OpaqueJSClass::StaticValuesTable* staticValues = jsClass->staticValues)
    422             if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep()))
    423                 if (JSObjectGetPropertyCallback getProperty = entry->getProperty) {
    424                     JSLock::DropAllLocks dropAllLocks;
    425                     if (JSValueRef value = getProperty(toRef(exec), thisRef, propertyNameRef, toRef(exec->exceptionSlot())))
    426                         return toJS(value);
    427                 }
    428 
    429     return throwError(exec, ReferenceError, "Static value property defined with NULL getProperty callback.");
    430 }
    431 
    432 JSValue* JSCallbackObject::staticFunctionGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
    433 {
    434     ASSERT(slot.slotBase()->inherits(&JSCallbackObject::info));
    435     JSCallbackObject* thisObj = static_cast<JSCallbackObject*>(slot.slotBase());
    436 
    437     if (JSValue* cachedOrOverrideValue = thisObj->getDirect(propertyName))
    438         return cachedOrOverrideValue;
    439 
    440     for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parentClass) {
    441         if (OpaqueJSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
    442             if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
    443                 if (JSObjectCallAsFunctionCallback callAsFunction = entry->callAsFunction) {
    444                     JSObject* o = new JSCallbackFunction(exec, callAsFunction, propertyName);
    445                     thisObj->putDirect(propertyName, o, entry->attributes);
    446                     return o;
    447                 }
    448             }
    449         }
    450     }
    451 
    452     return throwError(exec, ReferenceError, "Static function property defined with NULL callAsFunction callback.");
    453 }
    454 
    455 JSValue* JSCallbackObject::callbackGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
    456 {
    457     ASSERT(slot.slotBase()->inherits(&JSCallbackObject::info));
    458     JSCallbackObject* thisObj = static_cast<JSCallbackObject*>(slot.slotBase());
    459 
    460     JSObjectRef thisRef = toRef(thisObj);
    461     JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
    462 
    463     for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parentClass)
    464         if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) {
    465             JSLock::DropAllLocks dropAllLocks;
    466             if (JSValueRef value = getProperty(toRef(exec), thisRef, propertyNameRef, toRef(exec->exceptionSlot())))
    467                 return toJS(value);
    468         }
    469 
    470     return throwError(exec, ReferenceError, "hasProperty callback returned true for a property that doesn't exist.");
    471 }
     32// Define the two types of JSCallbackObjects we support.
     33template <> const ClassInfo JSCallbackObject<JSObject>::info = { "CallbackObject", 0, 0, 0 };
     34template <> const ClassInfo JSCallbackObject<JSGlobalObject>::info = { "CallbackGlobalObject", 0, 0, 0 };
    47235
    47336} // namespace KJS
Note: See TracChangeset for help on using the changeset viewer.