Changeset 15497 in webkit for trunk/JavaScriptCore/API


Ignore:
Timestamp:
Jul 17, 2006, 9:33:46 PM (19 years ago)
Author:
ggaren
Message:

Reviewed by Maciej.


  • Added automatic prototype creation for classes.


A class stores a weak reference to a prototype, which is cleared when
the prototype is garbage collected, to avoid a reference cycle.


We now have an attributes field in JSClassDefinition, that currently is
used only to override automatic prototype creation when you want to manage your
own prototypes, but can be extended in the future for other nefarious purposes.


Similarly, we have JSObjectMake and JSObjectMakeWithPrototype, the latter
allowing you to manage your own prototypes.


JSObjectMakeConstructor is more interesting now, able to make a constructor
on your behalf if you just give it a class.


  • Removed bogus old code from minidom.js.


  • Tweaked the headerdocs.


  • Added more GC testing, which caught some leaks, and tested more funny edge cases in lookup, which caught a lookup bug. Removed some testing we used to do with MyObject because it was redundant with the new, cool stuff.


While fixing the lookup bug I retracted this change:


"If a static setProperty callback returns 'false', to indicate that the
property was not set, we no longer forward the set request up the class
chain, because that's almost certainly not what the programmer expected."

Returning false when setting a static property is a little silly, but you can see
it being useful when shadowing a base class's static properties, and, regardless
of usefullness, this is the defined behavior of the setProperty callback.


  • Plus a little ASCII art, for the kids.
Location:
trunk/JavaScriptCore/API
Files:
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/API/JSBase.h

    r15486 r15497  
    4747typedef struct OpaqueJSPropertyNameArray* JSPropertyNameArrayRef;
    4848
    49 /*! @typedef JSPropertyNameAccumulatorRef A data type used to collect a JavaScript object's property names. */
     49/*! @typedef JSPropertyNameAccumulatorRef An ordered set used to collect the names of a JavaScript object's properties. */
    5050typedef struct OpaqueJSPropertyNameAccumulator* JSPropertyNameAccumulatorRef;
    5151
  • trunk/JavaScriptCore/API/JSCallbackConstructor.cpp

    r15482 r15497  
    3232const ClassInfo JSCallbackConstructor::info = { "CallbackConstructor", 0, 0, 0 };
    3333
    34 JSCallbackConstructor::JSCallbackConstructor(ExecState* exec, JSObjectCallAsConstructorCallback callback)
     34JSCallbackConstructor::JSCallbackConstructor(ExecState* exec, JSClassRef jsClass, JSObjectCallAsConstructorCallback callback)
    3535    : JSObject(exec->lexicalInterpreter()->builtinObjectPrototype())
     36    , m_class(jsClass)
    3637    , m_callback(callback)
    3738{
     39    if (m_class)
     40        JSClassRetain(jsClass);
     41}
     42
     43JSCallbackConstructor::~JSCallbackConstructor()
     44{
     45    if (m_class)
     46        JSClassRelease(m_class);
    3847}
    3948
     
    5059JSObject* JSCallbackConstructor::construct(ExecState* exec, const List &args)
    5160{
    52     JSContextRef execRef = toRef(exec);
     61    JSContextRef ctx = toRef(exec);
    5362    JSObjectRef thisRef = toRef(this);
    5463
    55     size_t argumentCount = args.size();
    56     JSValueRef arguments[argumentCount];
    57     for (size_t i = 0; i < argumentCount; i++)
    58         arguments[i] = toRef(args[i]);
    59     return toJS(m_callback(execRef, thisRef, argumentCount, arguments, toRef(exec->exceptionSlot())));
     64    if (m_callback) {
     65        size_t argumentCount = args.size();
     66        JSValueRef arguments[argumentCount];
     67        for (size_t i = 0; i < argumentCount; i++)
     68            arguments[i] = toRef(args[i]);
     69        return toJS(m_callback(ctx, thisRef, argumentCount, arguments, toRef(exec->exceptionSlot())));
     70    }
     71   
     72    return toJS(JSObjectMake(ctx, m_class, 0));
    6073}
    6174
  • trunk/JavaScriptCore/API/JSCallbackConstructor.h

    r15482 r15497  
    3636{
    3737public:
    38     JSCallbackConstructor(ExecState* exec, JSObjectCallAsConstructorCallback callback);
     38    JSCallbackConstructor(ExecState* exec, JSClassRef jsClass, JSObjectCallAsConstructorCallback callback);
     39    virtual ~JSCallbackConstructor();
    3940   
    4041    virtual bool implementsHasInstance() const;
     
    4950    JSCallbackConstructor(); // prevent default construction
    5051    JSCallbackConstructor(const JSCallbackConstructor&);
    51    
     52
     53    JSClassRef m_class;
    5254    JSObjectCallAsConstructorCallback m_callback;
    5355};
  • trunk/JavaScriptCore/API/JSCallbackObject.cpp

    r15484 r15497  
    144144                if (entry->attributes & kJSPropertyAttributeReadOnly)
    145145                    return;
    146                 if (JSObjectSetPropertyCallback setProperty = entry->setProperty)
    147                     setProperty(ctx, thisRef, propertyNameRef, valueRef, toRef(exec->exceptionSlot()));
    148                 else
     146                if (JSObjectSetPropertyCallback setProperty = entry->setProperty) {
     147                    if (setProperty(ctx, thisRef, propertyNameRef, valueRef, toRef(exec->exceptionSlot())))
     148                        return;
     149                } else
    149150                    throwError(exec, ReferenceError, "Writable static value property defined with NULL setProperty callback.");
    150151            }
  • trunk/JavaScriptCore/API/JSClassRef.cpp

    r15480 r15497  
    2525 */
    2626
     27#include "APICast.h"
     28#include "JSCallbackObject.h"
    2729#include "JSClassRef.h"
    2830#include "JSObjectRef.h"
     
    3133using namespace KJS;
    3234
    33 const JSClassDefinition kJSClassDefinitionNull = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
     35const JSClassDefinition kJSClassDefinitionEmpty = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    3436
    35 OpaqueJSClass::OpaqueJSClass(JSClassDefinition* definition)
     37OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass* protoClass)
    3638    : refCount(0)
    3739    , className(definition->className)
    3840    , parentClass(definition->parentClass)
     41    , prototypeClass(0)
    3942    , staticValues(0)
    4043    , staticFunctions(0)
     
    6871        }
    6972    }
     73       
     74    if (protoClass)
     75        prototypeClass = JSClassRetain(protoClass);
    7076}
    7177
     
    8187        delete staticFunctions;
    8288    }
     89   
     90    if (prototypeClass)
     91        JSClassRelease(prototypeClass);
    8392}
     93
     94JSClassRef OpaqueJSClass::createNoPrototype(const JSClassDefinition* definition)
     95{
     96    return new OpaqueJSClass(definition, 0);
     97}
     98
     99void clearReferenceToPrototype(JSObjectRef prototype)
     100{
     101    OpaqueJSClass* jsClass = static_cast<OpaqueJSClass*>(JSObjectGetPrivate(prototype));
     102    ASSERT(jsClass);
     103    jsClass->cachedPrototype = 0;
     104}
     105
     106JSClassRef OpaqueJSClass::create(const JSClassDefinition* definition)
     107{
     108    if (JSStaticFunction* staticFunctions = definition->staticFunctions) {
     109        // copy functions into a prototype class
     110        JSClassDefinition protoDefinition = kJSClassDefinitionEmpty;
     111        protoDefinition.staticFunctions = staticFunctions;
     112        protoDefinition.finalize = clearReferenceToPrototype;
     113        OpaqueJSClass* protoClass = new OpaqueJSClass(&protoDefinition, 0);
     114
     115        // remove functions from the original definition
     116        JSClassDefinition objectDefinition = *definition;
     117        objectDefinition.staticFunctions = 0;
     118        return new OpaqueJSClass(&objectDefinition, protoClass);
     119    }
     120
     121    return new OpaqueJSClass(definition, 0);
     122}
     123
     124/*!
     125// Doc here in case we make this public. (Hopefully we won't.)
     126@function
     127 @abstract Returns the prototype that will be used when constructing an object with a given class.
     128 @param ctx The execution context to use.
     129 @param jsClass A JSClass whose prototype you want to get.
     130 @result The JSObject prototype that was automatically generated for jsClass, or NULL if no prototype was automatically generated. This is the prototype that will be used when constructing an object using jsClass.
     131*/
     132JSObject* OpaqueJSClass::prototype(JSContextRef ctx)
     133{
     134    /* Class (C++) and prototype (JS) inheritance are parallel, so:
     135     *     (C++)      |        (JS)
     136     *   ParentClass  |   ParentClassPrototype
     137     *       ^        |          ^
     138     *       |        |          |
     139     *  DerivedClass  |  DerivedClassPrototype
     140     */
     141   
     142    if (!prototypeClass)
     143        return 0;
     144   
     145    ExecState* exec = toJS(ctx);
     146   
     147    if (!cachedPrototype) {
     148        // Recursive, but should be good enough for our purposes
     149        JSObject* parentPrototype = 0;
     150        if (parentClass)
     151            parentPrototype = parentClass->prototype(ctx); // can be null
     152        if (!parentPrototype)
     153            parentPrototype = exec->dynamicInterpreter()->builtinObjectPrototype();
     154        cachedPrototype = new JSCallbackObject(exec, prototypeClass, parentPrototype, this); // set ourself as the object's private data, so it can clear our reference on destruction
     155    }
     156    return cachedPrototype;
     157}
  • trunk/JavaScriptCore/API/JSClassRef.h

    r15480 r15497  
    2929
    3030#include "JSObjectRef.h"
    31 #include "HashMap.h"
    32 #include "ustring.h"
     31
     32#include <kjs/object.h>
     33#include <kjs/protect.h>
     34#include <kjs/ustring.h>
     35#include <wtf/HashMap.h>
    3336
    3437struct StaticValueEntry {
     
    5457
    5558struct OpaqueJSClass {
    56     OpaqueJSClass(JSClassDefinition*);
     59    static OpaqueJSClass* create(const JSClassDefinition*);
     60    static OpaqueJSClass* createNoPrototype(const JSClassDefinition*);
    5761    ~OpaqueJSClass();
     62   
     63    KJS::JSObject* prototype(JSContextRef ctx);
    5864   
    5965    typedef HashMap<RefPtr<KJS::UString::Rep>, StaticValueEntry*> StaticValuesTable;
     
    6470    KJS::UString className;
    6571    OpaqueJSClass* parentClass;
    66        
     72    OpaqueJSClass* prototypeClass;
     73
    6774    StaticValuesTable* staticValues;
    6875    StaticFunctionsTable* staticFunctions;
     
    7986    JSObjectHasInstanceCallback hasInstance;
    8087    JSObjectConvertToTypeCallback convertToType;
     88
     89private:
     90    OpaqueJSClass();
     91    OpaqueJSClass(const OpaqueJSClass&);
     92    OpaqueJSClass(const JSClassDefinition*, OpaqueJSClass* protoClass);
     93   
     94    friend void clearReferenceToPrototype(JSObjectRef prototype);
     95    KJS::JSObject* cachedPrototype;
    8196};
    8297
  • trunk/JavaScriptCore/API/JSNode.c

    r15484 r15497  
    3131#include "UnusedParam.h"
    3232
    33 static JSClassRef JSNode_class(JSContextRef context);
    34 
    35 static JSValueRef JSNodePrototype_appendChild(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
     33static JSValueRef JSNode_appendChild(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
    3634{
    3735    UNUSED_PARAM(context);
     
    5755}
    5856
    59 static JSValueRef JSNodePrototype_removeChild(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
     57static JSValueRef JSNode_removeChild(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
    6058{
    6159    UNUSED_PARAM(context);
     
    7775}
    7876
    79 static JSValueRef JSNodePrototype_replaceChild(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
     77static JSValueRef JSNode_replaceChild(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
    8078{
    8179    UNUSED_PARAM(context);
     
    9997}
    10098
    101 static JSStaticFunction JSNodePrototype_staticFunctions[] = {
    102     { "appendChild", JSNodePrototype_appendChild, kJSPropertyAttributeDontDelete },
    103     { "removeChild", JSNodePrototype_removeChild, kJSPropertyAttributeDontDelete },
    104     { "replaceChild", JSNodePrototype_replaceChild, kJSPropertyAttributeDontDelete },
     99static JSStaticFunction JSNode_staticFunctions[] = {
     100    { "appendChild", JSNode_appendChild, kJSPropertyAttributeDontDelete },
     101    { "removeChild", JSNode_removeChild, kJSPropertyAttributeDontDelete },
     102    { "replaceChild", JSNode_replaceChild, kJSPropertyAttributeDontDelete },
    105103    { 0, 0, 0 }
    106104};
    107 
    108 static JSClassRef JSNodePrototype_class(JSContextRef context)
    109 {
    110     static JSClassRef jsClass;
    111     if (!jsClass) {
    112         JSClassDefinition definition = kJSClassDefinitionNull;
    113         definition.staticFunctions = JSNodePrototype_staticFunctions;
    114         jsClass = JSClassCreate(&definition);
    115     }
    116     return jsClass;
    117 }
    118105
    119106static JSValueRef JSNode_getNodeType(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
     
    173160}
    174161
    175 static JSClassRef JSNode_class(JSContextRef context)
     162JSClassRef JSNode_class(JSContextRef context)
    176163{
    177164    static JSClassRef jsClass;
    178165    if (!jsClass) {
    179         JSClassDefinition definition = kJSClassDefinitionNull;
     166        JSClassDefinition definition = kJSClassDefinitionEmpty;
    180167        definition.staticValues = JSNode_staticValues;
     168        definition.staticFunctions = JSNode_staticFunctions;
    181169        definition.initialize = JSNode_initialize;
    182170        definition.finalize = JSNode_finalize;
     
    187175}
    188176
    189 JSObjectRef JSNode_prototype(JSContextRef context)
    190 {
    191     static JSObjectRef prototype;
    192     if (!prototype) {
    193         prototype = JSObjectMake(context, JSNodePrototype_class(context), NULL);
    194         JSValueProtect(context, prototype);
    195     }
    196     return prototype;
    197 }
    198 
    199177JSObjectRef JSNode_new(JSContextRef context, Node* node)
    200178{
    201     return JSObjectMakeWithData(context, JSNode_class(context), JSNode_prototype(context), node);
     179    return JSObjectMake(context, JSNode_class(context), node);
    202180}
    203181
  • trunk/JavaScriptCore/API/JSNode.h

    r15482 r15497  
    3232
    3333extern JSObjectRef JSNode_new(JSContextRef context, Node* node);
    34 extern JSObjectRef JSNode_prototype(JSContextRef context);
     34extern JSClassRef JSNode_class(JSContextRef context);
    3535extern JSObjectRef JSNode_construct(JSContextRef context, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
    3636
  • trunk/JavaScriptCore/API/JSNodeList.c

    r15484 r15497  
    2929#include "UnusedParam.h"
    3030
    31 static JSValueRef JSNodeListPrototype_item(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
     31static JSValueRef JSNodeList_item(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
    3232{
    3333    if (argumentCount > 0) {
     
    4242}
    4343
    44 static JSStaticFunction JSNodeListPrototype_staticFunctions[] = {
    45     { "item", JSNodeListPrototype_item, kJSPropertyAttributeDontDelete },
     44static JSStaticFunction JSNodeList_staticFunctions[] = {
     45    { "item", JSNodeList_item, kJSPropertyAttributeDontDelete },
    4646    { 0, 0, 0 }
    4747};
    48 
    49 static JSClassRef JSNodeListPrototype_class(JSContextRef context)
    50 {
    51     static JSClassRef jsClass;
    52     if (!jsClass) {
    53         JSClassDefinition definition = kJSClassDefinitionNull;
    54         definition.staticFunctions = JSNodeListPrototype_staticFunctions;
    55         jsClass = JSClassCreate(&definition);
    56     }
    57    
    58     return jsClass;
    59 }
    6048
    6149static JSValueRef JSNodeList_length(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
     
    10997    static JSClassRef jsClass;
    11098    if (!jsClass) {
    111         JSClassDefinition definition = kJSClassDefinitionNull;
     99        JSClassDefinition definition = kJSClassDefinitionEmpty;
    112100        definition.staticValues = JSNodeList_staticValues;
     101        definition.staticFunctions = JSNodeList_staticFunctions;
    113102        definition.getProperty = JSNodeList_getProperty;
    114103        definition.initialize = JSNodeList_initialize;
     
    121110}
    122111
    123 static JSObjectRef JSNodeList_prototype(JSContextRef context)
    124 {
    125     static JSObjectRef prototype;
    126     if (!prototype) {
    127         prototype = JSObjectMake(context, JSNodeListPrototype_class(context), NULL);
    128         JSValueProtect(context, prototype);
    129     }
    130     return prototype;
    131 }
    132 
    133112JSObjectRef JSNodeList_new(JSContextRef context, NodeList* nodeList)
    134113{
    135     return JSObjectMakeWithData(context, JSNodeList_class(context), JSNodeList_prototype(context), nodeList);
     114    return JSObjectMake(context, JSNodeList_class(context), nodeList);
    136115}
  • trunk/JavaScriptCore/API/JSObjectRef.cpp

    r15484 r15497  
    4444JSClassRef JSClassCreate(JSClassDefinition* definition)
    4545{
    46     JSClassRef jsClass = new OpaqueJSClass(definition);
     46    JSClassRef jsClass = (definition->attributes & kJSClassAttributeNoPrototype)
     47        ? OpaqueJSClass::createNoPrototype(definition)
     48        : OpaqueJSClass::create(definition);
     49   
    4750    return JSClassRetain(jsClass);
    4851}
     
    6063}
    6164
    62 JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype)
    63 {
    64     return JSObjectMakeWithData(ctx, jsClass, prototype, 0);
    65 }
    66 
    67 JSObjectRef JSObjectMakeWithData(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype, void* data)
     65JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, void* data)
     66{
     67    JSLock lock;
     68    ExecState* exec = toJS(ctx);
     69
     70    JSValue* jsPrototype = jsClass
     71        ? jsClass->prototype(ctx)
     72        : exec->lexicalInterpreter()->builtinObjectPrototype();
     73
     74    return JSObjectMakeWithPrototype(ctx, jsClass, data, toRef(jsPrototype));
     75}
     76
     77JSObjectRef JSObjectMakeWithPrototype(JSContextRef ctx, JSClassRef jsClass, void* data, JSValueRef prototype)
    6878{
    6979    JSLock lock;
     
    7888        return toRef(new JSObject(jsPrototype)); // slightly more efficient
    7989   
    80     return toRef(new JSCallbackObject(exec, jsClass, jsPrototype, data)); // initialize can't throw
     90    return toRef(new JSCallbackObject(exec, jsClass, jsPrototype, data));
    8191}
    8292
     
    90100}
    91101
    92 JSObjectRef JSObjectMakeConstructorWithCallback(JSContextRef ctx, JSValueRef prototype, JSObjectCallAsConstructorCallback callAsConstructor)
    93 {
    94     JSLock lock;
    95     ExecState* exec = toJS(ctx);
    96     JSValue* jsPrototype = toJS(prototype);
    97    
    98     if (!jsPrototype)
    99         jsPrototype = exec->dynamicInterpreter()->builtinObjectPrototype();
    100    
    101     JSObject* constructor = new JSCallbackConstructor(exec, callAsConstructor);
     102JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsClass, JSObjectCallAsConstructorCallback callAsConstructor)
     103{
     104    JSLock lock;
     105    ExecState* exec = toJS(ctx);
     106   
     107    JSValue* jsPrototype = jsClass
     108        ? jsClass->prototype(ctx)
     109        : exec->dynamicInterpreter()->builtinObjectPrototype();
     110   
     111    JSObject* constructor = new JSCallbackConstructor(exec, jsClass, callAsConstructor);
    102112    constructor->put(exec, prototypePropertyName, jsPrototype, DontEnum|DontDelete|ReadOnly);
    103113    return toRef(constructor);
  • trunk/JavaScriptCore/API/JSObjectRef.h

    r15486 r15497  
    5858typedef unsigned JSPropertyAttributes;
    5959
     60/*!
     61@enum JSClassAttribute
     62@constant kJSClassAttributeNone Specifies that a class has no special attributes.
     63@constant kJSClassAttributeNoPrototype Specifies that a class should not generate a prototype object. Use kJSClassAttributeNoPrototype in combination with JSObjectMakeWithPrototype to manage prototypes manually.
     64*/
     65enum {
     66    kJSClassAttributeNone = 0,
     67    kJSClassAttributeNoPrototype = 1 << 1
     68};
     69
     70/*!
     71@typedef JSClassAttributes
     72@abstract A set of JSClassAttributes. Combine multiple attributes by logically ORing them together.
     73*/
     74typedef unsigned JSClassAttributes;
     75
    6076/*!
    6177@typedef JSObjectInitializeCallback
     
    161177/*!
    162178@typedef JSObjectGetPropertyNamesCallback
    163 @abstract The callback invoked to get the names of an object's properties.
    164 @param ctx The execution context to use.
    165 @param object The JSObject whose property names need to be appended to propertyNames.
    166 @param accumulator A JavaScript property name accumulator, to which the object should add the names of its properties.
     179@abstract The callback invoked when collecting the names of an object's properties.
     180@param ctx The execution context to use.
     181@param object The JSObject whose property names are being collected.
     182@param accumulator A JavaScript property name accumulator in which to accumulate the names of object's properties.
    167183@discussion If you named your function GetPropertyNames, you would declare it like this:
    168184
    169185void GetPropertyNames(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccumulatorRef accumulator);
    170186
    171 Use JSPropertyNameAccumulatorAddName to add property names to accumulator.
    172 
    173 Property lists are used by JSPropertyEnumerators and JavaScript for...in loops.
    174 
    175 It's only necessary to add names of properties that you handle
    176 specially in your own get / set callbacks. Static property names,
    177 names of standard JS properties, and properties from the prototype
    178 will be added automatically.
     187Property name accumulators are used by JSObjectCopyPropertyNames and JavaScript for...in loops.
     188
     189Use JSPropertyNameAccumulatorAddName to add property names to accumulator. A class's getPropertyNames callback only needs to provide the names of properties that the class vends through a custom getProperty or setProperty callback. Other properties, including statically declared properties, properties vended by other classes, and properties belonging to object's prototype, are added independently.
    179190*/
    180191typedef void
     
    195206JSValueRef CallAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
    196207
    197 If your callback were invoked by the JavaScript expression 'myObject.myMemberFunction()', function would be set to myMemberFunction, and thisObject would be set to myObject.
     208If your callback were invoked by the JavaScript expression 'myObject.myFunction()', function would be set to myFunction, and thisObject would be set to myObject.
    198209
    199210If this callback is NULL, calling your object as a function will throw an exception.
     
    215226JSObjectRef CallAsConstructor(JSContextRef ctx, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
    216227
    217 If your callback were invoked by the JavaScript expression 'new myConstructorFunction()', constructor would be set to myConstructorFunction.
     228If your callback were invoked by the JavaScript expression 'new myConstructor()', constructor would be set to myConstructor.
    218229
    219230If this callback is NULL, using your object as a constructor in a 'new' expression will throw an exception.
     
    292303/*!
    293304@struct JSClassDefinition
    294 @abstract This structure contains properties and callbacks that define a type of object. All fields are optional. Any field may be NULL.
     305@abstract This structure contains properties and callbacks that define a type of object. All fields other than the version field are optional. Any pointer may be NULL.
    295306@field version The version number of this structure. The current version is 0.
     307@field attributes A logically ORed set of JSClassAttributes to give to the class.
    296308@field className A null-terminated UTF8 string containing the class's name.
    297309@field parentClass A JSClass to set as the class's parent class. Pass NULL use the default object class.
     
    304316@field setProperty The callback invoked when setting a property's value.
    305317@field deleteProperty The callback invoked when deleting a property.
    306 @field addPropertiesToList The callback invoked when adding an object's properties to a property list.
     318@field getPropertyNames The callback invoked when collecting the names of an object's properties.
    307319@field callAsFunction The callback invoked when an object is called as a function.
    308320@field hasInstance The callback invoked when an object is used as the target of an 'instanceof' expression.
    309321@field callAsConstructor The callback invoked when an object is used as a constructor in a 'new' expression.
    310322@field convertToType The callback invoked when converting an object to a particular JavaScript type.
    311 @discussion The staticValues and staticFunctions arrays are the simplest and most efficient means for vending custom properties. Statically declared properties autmatically service requests like get, set, and enumerate. Property access callbacks are required only to implement unusual properties, like array indexes, whose names are not known at compile-time.
     323@discussion The staticValues and staticFunctions arrays are the simplest and most efficient means for vending custom properties. Statically declared properties autmatically service requests like getProperty, setProperty, and getPropertyNames. Property access callbacks are required only to implement unusual properties, like array indexes, whose names are not known at compile-time.
    312324
    313325If you named your getter function "GetX" and your setter function "SetX", you would declare a JSStaticValue array containing "X" like this:
     
    318330};
    319331
    320 Standard JavaScript practice calls for storing functions in prototype objects, so derived objects can share them. Therefore, it is common for prototype classes to have function properties but no value properties, and for object classes to have value properties but no function properties.
     332Standard JavaScript practice calls for storing functions in prototype objects, so derived objects can share them. Therefore, it is common for prototypes to have function properties but no value properties, and for objects to have value properties but no function properties. The default behavior of JSClassCreate is to follow this idiom, automatically generating a prototype in which to store the class's function properties. The kJSClassAttributeNoPrototype attribute overrides the idiom, specifying that all supplied function and value properties should be stored directly in the object.
    321333
    322334A NULL callback specifies that the default object callback should substitute, except in the case of hasProperty, where it specifies that getProperty should substitute.
     
    324336typedef struct {
    325337    int                                 version; // current (and only) version is 0
     338    JSClassAttributes                   attributes;
    326339
    327340    const char*                         className;
     
    345358
    346359/*!
    347 @const kJSClassDefinitionNull
    348 @abstract A JSClassDefinition structure of the current version, filled with NULL pointers.
     360@const kJSClassDefinitionEmpty
     361@abstract A JSClassDefinition structure of the current version, filled with NULL pointers and having no attributes.
    349362@discussion Use this constant as a convenience when creating class definitions. For example, to create a class definition with only a finalize method:
    350363
    351 JSClassDefinition definition = kJSClassDefinitionNull;
     364JSClassDefinition definition = kJSClassDefinitionEmpty;
    352365
    353366definition.finalize = Finalize;
    354367*/
    355 extern const JSClassDefinition kJSClassDefinitionNull;
     368extern const JSClassDefinition kJSClassDefinitionEmpty;
    356369
    357370/*!
     
    359372@abstract Creates a JavaScript class suitable for use with JSObjectMake.
    360373@param definition A JSClassDefinition that defines the class.
    361 @result A JSClass with the given definition's name, properties, callbacks, and parent class. Ownership follows the Create Rule.
     374@result A JSClass with the given definition. Ownership follows the Create Rule.
    362375*/
    363376JSClassRef JSClassCreate(JSClassDefinition* definition);
     
    370383*/
    371384JSClassRef JSClassRetain(JSClassRef jsClass);
     385
    372386/*!
    373387@function
     
    382396@param ctx The execution context to use.
    383397@param jsClass The JSClass to assign to the object. Pass NULL to use the default object class.
    384 @param prototype The prototype to assign to the object. Pass NULL to use the default object prototype.
    385 @result A JSObject with the given class, prototype, and private data.
    386 @discussion The default object class does not allocate storage for private data, so you must provide a non-NULL JSClass if you want your object to be able to store private data.
    387 */
    388 JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype);
    389 
    390 /*!
    391 @function
    392 @abstract Creates a JavaScript object.
     398@param data A void* to set as the object's private data. Pass NULL to specify no private data.
     399@result A JSObject with the given class and private data.
     400@discussion JSObjectMake assigns jsClass's automatically generated prototype to the object it creates. If jsClass has no automatically generated prototype, JSObjectMake uses the default object prototype.
     401
     402data is set on the created object before the intialize methods in its class chain are called. This enables the initialize methods to retrieve and manipulate data through JSObjectGetPrivate.
     403
     404The default object class does not allocate storage for private data, so you must provide a non-NULL jsClass if you want your object to be able to store private data.
     405*/
     406JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, void* data);
     407
     408/*!
     409@function
     410@abstract Creates a JavaScript object with a given prototype.
    393411@param ctx The execution context to use.
    394412@param jsClass The JSClass to assign to the object. Pass NULL to use the default object class.
    395413@param prototype The prototype to assign to the object. Pass NULL to use the default object prototype.
    396414@param data A void* to set as the object's private data. Pass NULL to specify no private data.
    397 @param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
    398 @result A JSObject with the given class, prototype, and private data.
    399 @discussion The default object class does not allocate storage for private data, so you must provide a non-NULL JSClass if you want your object to be able to store private data.
     415@result A JSObject with the given class, private data, and prototype.
     416@discussion Use JSObjectMakeWithPrototype in combination with kJSClassAttributeNoPrototype to manage prototypes manually.
    400417 
    401 data will be set on the created object before the intialize methods in its class chain are called. This enables the initialize methods to retrieve and manipulate data through JSObjectGetPrivate.
    402 */
    403 JSObjectRef JSObjectMakeWithData(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype, void* data);
     418data is set on the created object before the intialize methods in its class chain are called. This enables the initialize methods to retrieve and manipulate data through JSObjectGetPrivate.
     419
     420The default object class does not allocate storage for private data, so you must provide a non-NULL JSClass if you want your object to be able to store private data.
     421*/
     422JSObjectRef JSObjectMakeWithPrototype(JSContextRef ctx, JSClassRef jsClass, void* data, JSValueRef prototype);
    404423
    405424/*!
     
    415434/*!
    416435@function
    417 @abstract Convenience method for creating a JavaScript constructor with a given callback as its implementation.
    418 @param ctx The execution context to use.
    419 @param prototype A JSValue to use as the constructor's .prototype property. This should be the same value your constructor will set as the prototype of the objects it constructs.
    420 @param callAsConstructor The JSObjectCallAsConstructorCallback to invoke when the constructor is used in a 'new' expression.
     436@abstract Convenience method for creating a JavaScript constructor.
     437@param ctx The execution context to use.
     438@param jsClass A JSClass that is the class your constructor will assign to the objects its constructs. jsClass will be used to set the constructor's .prototype property, and to evaluate 'instanceof' expressions. Pass NULL to use the default object class.
     439@param callAsConstructor A JSObjectCallAsConstructorCallback to invoke when your constructor is used in a 'new' expression. Pass NULL to use the default object constructor.
    421440@result A JSObject that is a constructor. The object's prototype will be the default object prototype.
    422 */
    423 JSObjectRef JSObjectMakeConstructorWithCallback(JSContextRef ctx, JSValueRef prototype, JSObjectCallAsConstructorCallback callAsConstructor);
     441@discussion The default object constructor takes no arguments and constructs an object of class jsClass with no private data.
     442*/
     443JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsClass, JSObjectCallAsConstructorCallback callAsConstructor);
    424444
    425445/*!
     
    444464@param ctx  The execution context to use.
    445465@param object A JSObject whose prototype you want to get.
    446 @result A JSValue containing the object's prototype.
     466@result A JSValue that is the object's prototype.
    447467*/
    448468JSValueRef JSObjectGetPrototype(JSContextRef ctx, JSObjectRef object);
     
    505525@param ctx The execution context to use.
    506526@param object The JSObject whose property you want to get.
    507 @param propertyIndex The property's name as a number.
     527@param propertyIndex An integer value that is the property's name.
    508528@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
    509529@result The property's value if object has the property, otherwise the undefined value.
    510 @discussion Calling JSObjectGetPropertyAtIndex is equivalent to calling JSObjectGetProperty with a string containing propertyIndex, but it enables optimized access to JavaScript arrays.
     530@discussion Calling JSObjectGetPropertyAtIndex is equivalent to calling JSObjectGetProperty with a string containing propertyIndex, but JSObjectGetPropertyAtIndex provides optimized access to numeric properties.
    511531*/
    512532JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef* exception);
     
    520540@param value A JSValue to use as the property's value.
    521541@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
    522 @discussion Calling JSObjectSetPropertyAtIndex is equivalent to calling JSObjectSetProperty with a string containing propertyIndex, but it enables optimized access to JavaScript arrays.
     542@discussion Calling JSObjectSetPropertyAtIndex is equivalent to calling JSObjectSetProperty with a string containing propertyIndex, but JSObjectSetPropertyAtIndex provides optimized access to numeric properties.
    523543*/
    524544void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef value, JSValueRef* exception);
     
    535555@function
    536556@abstract Sets a pointer to private data on an object.
    537 @param object A JSObject whose private data you want to set.
     557@param object The JSObject whose private data you want to set.
    538558@param data A void* to set as the object's private data.
    539 @result true if the object can store private data, otherwise false.
     559@result true if object can store private data, otherwise false.
    540560@discussion The default object class does not allocate storage for private data. Only objects created with a non-NULL JSClass can store private data.
    541561*/
     
    558578@param thisObject The object to use as "this," or NULL to use the global object as "this."
    559579@param argumentCount An integer count of the number of arguments in arguments.
    560 @param arguments A JSValue array of the  arguments to pass to the function. Pass NULL if argumentCount is 0.
     580@param arguments A JSValue array of arguments to pass to the function. Pass NULL if argumentCount is 0.
    561581@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
    562582@result The JSValue that results from calling object as a function, or NULL if an exception is thrown or object is not a function.
     
    579599@param object The JSObject to call as a constructor.
    580600@param argumentCount An integer count of the number of arguments in arguments.
    581 @param arguments A JSValue array of the  arguments to pass to the function. Pass NULL if argumentCount is 0.
     601@param arguments A JSValue array of arguments to pass to the constructor. Pass NULL if argumentCount is 0.
    582602@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
    583603@result The JSObject that results from calling object as a constructor, or NULL if an exception is thrown or object is not a constructor.
     
    587607/*!
    588608@function
    589 @abstract Get the names of all enumerable properties of an object.
    590 @param ctx The execution context to use.
    591 @param object The object from which to get property names.
    592 @result A JSPropertyNameArray containing the names of all the object's enumerable properties.
     609@abstract Gets the names of an object's enumerable properties.
     610@param ctx The execution context to use.
     611@param object The object whose property names you want to get.
     612@result A JSPropertyNameArray containing the names object's enumerable properties.
    593613*/
    594614JSPropertyNameArrayRef JSObjectCopyPropertyNames(JSContextRef ctx, JSObjectRef object);
     
    611631/*!
    612632@function
    613 @abstract Get the number of items in a JavaScript property name array.
     633@abstract Gets a count of the number of items in a JavaScript property name array.
    614634@param array The array from which to retrieve the count.
    615 @result The count of items in the array.
     635@result An integer count of the number of names in array.
    616636*/
    617637size_t JSPropertyNameArrayGetCount(JSPropertyNameArrayRef array);
     
    619639/*!
    620640@function
    621 @abstract Get a single item from a JavaScript property name array.
    622 @param array The array from which to retrieve a property name.
     641@abstract Gets a property name at a given index in a JavaScript property name array.
     642@param array The array from which to retrieve the property name.
    623643@param index The index of the property name to retrieve.
    624 @result A JSStringRef containing the name of the property.
     644@result A JSStringRef containing the property name.
    625645*/
    626646JSStringRef JSPropertyNameArrayGetNameAtIndex(JSPropertyNameArrayRef array, size_t index);
     
    628648/*!
    629649@function
    630 @abstract Add a property name - useful while getting the property names for an object.
    631 @param accumulator The accumulator object to which to add the property.
    632 @param propertyName The new property to add.
     650@abstract Adds a property name to a JavaScript property name accumulator.
     651@param accumulator The accumulator object to which to add the property name.
     652@param propertyName The property name to add.
    633653*/
    634654void JSPropertyNameAccumulatorAddName(JSPropertyNameAccumulatorRef accumulator, JSStringRef propertyName);
  • trunk/JavaScriptCore/API/JSStringRef.h

    r15437 r15497  
    151151/*!
    152152@function
    153 @abstract         Creates a CFString form a JavaScript string.
     153@abstract         Creates a CFString from a JavaScript string.
    154154@param alloc      The alloc parameter to pass to CFStringCreate.
    155155@param string     The JSString to copy into the new CFString.
  • trunk/JavaScriptCore/API/JSValueRef.h

    r15481 r15497  
    120120/*!
    121121@function
    122 @abstract       Tests whether a JavaScript value is an object with a given
    123 @param ctx  The execution context to use.
    124  class in its class chain.
    125 @param value    The JSValue to test.
    126  @result        true if value is an object and has jsClass in its class chain,
    127  otherwise false.
     122@abstract Tests whether a JavaScript value is an object with a given class in its class chain.
     123@param ctx The execution context to use.
     124@param value The JSValue to test.
     125@param jsClass The JSClass to test against.
     126@result true if value is an object and has jsClass in its class chain, otherwise false.
    128127*/
    129128bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass);
     
    253252/*!
    254253@function
    255 @abstract       Protects a JavaScript value from garbage collection.
    256 @param ctx  The execution context to use.
    257 @param value    The JSValue to protect.
    258 @discussion     A value may be protected multiple times and must be unprotected an
    259  equal number of times before becoming eligible for garbage collection.
     254@abstract Protects a JavaScript value from garbage collection.
     255@param ctx The execution context to use.
     256@param value The JSValue to protect.
     257@discussion Use this method when you want to store a JSValue in a global or on the heap, where the garbage collector will not be able to discover your reference to it.
     258 
     259A value may be protected multiple times and must be unprotected an equal number of times before becoming eligible for garbage collection.
    260260*/
    261261void JSValueProtect(JSContextRef ctx, JSValueRef value);
  • trunk/JavaScriptCore/API/minidom.c

    r15484 r15497  
    4545   
    4646    JSStringRef node = JSStringCreateWithUTF8CString("Node");
    47     JSObjectSetProperty(context, globalObject, node, JSObjectMakeConstructorWithCallback(context, JSNode_prototype(context), JSNode_construct), kJSPropertyAttributeNone, NULL);
     47    JSObjectSetProperty(context, globalObject, node, JSObjectMakeConstructor(context, JSNode_class(context), JSNode_construct), kJSPropertyAttributeNone, NULL);
    4848    JSStringRelease(node);
    4949   
  • trunk/JavaScriptCore/API/minidom.js

    r15484 r15497  
    2424 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2525 */
    26 
    27 // For browser-based testing
    28 if (typeof window != 'undefined') {
    29     /*
    30     The methods and constructors below approximate what that the native host should provide
    31 
    32     print(string);
    33 
    34     Node
    35         |-- TextNode
    36         |-- Element
    37             |-- RootElement
    38             |-- HeroElement
    39             |-- VillainElement
    40             |-- NameElement
    41             |-- WeaponElement
    42         |-- Document
    43     */
    44      
    45     function print(string, indentLevel)
    46     {
    47         document.getElementById('pre').appendChild(document.createTextNode(string));
    48     }
    49    
    50     Node = function()
    51     {
    52         this.__defineGetter__("childNodes", function() {
    53             if (!this._childNodes)
    54                 this._childNodes = new Array();
    55             return this._childNodes;
    56         });
    57         this.__defineGetter__("firstChild", function () {
    58             return this.childNodes[0];
    59         });
    60     }
    61 
    62     Node.prototype.nodeType = "Node";
    63 
    64     Node.prototype.appendChild = function(child) {
    65         this.childNodes.push(child);
    66     }
    67    
    68     Node.prototype.serialize = function(numSpaces) {
    69         function printSpaces(n)
    70         {
    71             for (var i = 0; i < n; i++) // >
    72             print(" ");
    73         }
    74 
    75         printSpaces(numSpaces);
    76         print('<' + this.nodeType + '>' + '\n');
    77        
    78         var childNodesLength = this.childNodes.length;
    79         for (var i = 0; i < childNodesLength; i++) //>
    80             this.childNodes[i].serialize(numSpaces + 4);
    81        
    82         printSpaces(numSpaces);
    83         print('</' + this.nodeType + '>\n');
    84     }
    85 
    86     TextNode = function(text)
    87     {
    88         this.text = text;
    89     }
    90 
    91     TextNode.prototype = new Node();
    92    
    93     TextNode.prototype.nodeType = "Text";
    94    
    95     TextNode.prototype.serialize = function(numSpaces) {
    96         for (var i = 0; i < numSpaces; i++) // >
    97             print(" ");
    98         print(this.text + '\n');
    99     }
    100 
    101     Element = function()
    102     {
    103     }
    104    
    105     Element.prototype = new Node();
    106    
    107     Element.prototype.nodeType = "Element";
    108 
    109     RootElement = function()
    110     {
    111     }
    112    
    113     RootElement.prototype = new Element();
    114 
    115     RootElement.prototype.nodeType = "Root";
    116    
    117     HeroElement = function()
    118     {
    119     }
    120    
    121     HeroElement.prototype = new Element();
    122 
    123     HeroElement.prototype.nodeType = "Hero";
    124 
    125     VillainElement = function()
    126     {
    127     }
    128    
    129     VillainElement.prototype = new Element();
    130 
    131     VillainElement.prototype.nodeType = "Villain";
    132 
    133     NameElement = function()
    134     {
    135     }
    136    
    137     NameElement.prototype = new Element();
    138 
    139     NameElement.prototype.nodeType = "Name";
    140 
    141     WeaponElement = function()
    142     {
    143     }
    144    
    145     WeaponElement.prototype = new Element();
    146 
    147     WeaponElement.prototype.nodeType = "Weapon";
    148 
    149     Document = function()
    150     {
    151     }
    152 
    153     Document.prototype = new Node();
    154 
    155     Document.prototype.serialize = function() {
    156         this.firstChild.serialize(0);
    157     }
    158    
    159     Document.prototype.createElement = function(elementType) {
    160         return eval('new ' + elementType + 'Element()');
    161     }
    162 
    163     Document.prototype.createTextNode = function(text) {
    164         return new TextNode(text);
    165     }
    166 }
    16726
    16827function shouldBe(a, b)
     
    248107   
    249108    print(Node);
    250 
    251     /*
    252     var element, name, weapon;
    253    
    254     var document = new Document();
    255     document.appendChild(document.createElement('Root'));
    256 
    257     // Tank Girl
    258     element = document.createElement('Hero');
    259 
    260     name = document.createElement('Name');
    261     name.appendChild(document.createTextNode('Tank Girl'));
    262     element.appendChild(name);
    263    
    264     weapon = document.createElement('Weapon');
    265     weapon.appendChild(document.createTextNode('Tank'));
    266     element.appendChild(weapon);
    267    
    268     weapon = document.createElement('Weapon');
    269     weapon.appendChild(document.createTextNode('Attitude'));
    270     element.appendChild(weapon);
    271    
    272     weapon = document.createElement('Weapon');
    273     weapon.appendChild(document.createTextNode('Army of genetically engineered super-kangaroos'));
    274     element.appendChild(weapon);
    275    
    276     document.firstChild.appendChild(element);
    277 
    278 
    279     // Skeletor
    280     element = document.createElement('Villain');
    281 
    282     name = document.createElement('Name');
    283     name.appendChild(document.createTextNode('Skeletor'));
    284     element.appendChild(name);
    285    
    286     weapon = document.createElement('Weapon');
    287     weapon.appendChild(document.createTextNode('Havok Staff'));
    288     element.appendChild(weapon);
    289    
    290     weapon = document.createElement('Weapon');
    291     weapon.appendChild(document.createTextNode('Motley crew of henchmen'));
    292     element.appendChild(weapon);
    293    
    294     document.firstChild.appendChild(element);
    295 
    296     // Serialize
    297     document.serialize();
    298     */
    299109}
    300110
  • trunk/JavaScriptCore/API/testapi.c

    r15484 r15497  
    3434#include <assert.h>
    3535#include <math.h>
     36#include <setjmp.h>
    3637
    3738static JSGlobalContextRef context = 0;
     
    100101/* MyObject pseudo-class */
    101102
    102 static bool didInitialize = false;
    103 static void MyObject_initialize(JSContextRef context, JSObjectRef object)
    104 {
    105     UNUSED_PARAM(context);
    106     UNUSED_PARAM(object);
    107     didInitialize = true;
    108 }
    109 
    110103static bool MyObject_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName)
    111104{
     
    242235}
    243236
    244 static bool MyObject_didFinalize = false;
    245 static void MyObject_finalize(JSObjectRef object)
    246 {
    247     UNUSED_PARAM(context);
    248     UNUSED_PARAM(object);
    249     MyObject_didFinalize = true;
    250 }
    251 
    252237static JSStaticValue evilStaticValues[] = {
    253238    { "nullGetSet", 0, 0, kJSPropertyAttributeNone },
     
    262247JSClassDefinition MyObject_definition = {
    263248    0,
     249    kJSClassAttributeNone,
    264250   
    265251    "MyObject",
     
    269255    evilStaticFunctions,
    270256   
    271     MyObject_initialize,
    272     MyObject_finalize,
     257    NULL,
     258    NULL,
    273259    MyObject_hasProperty,
    274260    MyObject_getProperty,
     
    291277}
    292278
     279static JSValueRef Base_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
     280{
     281    UNUSED_PARAM(ctx);
     282    UNUSED_PARAM(object);
     283    UNUSED_PARAM(propertyName);
     284
     285    return JSValueMakeNumber(ctx, 1); // distinguish base get form derived get
     286}
     287
     288static bool Base_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
     289{
     290    UNUSED_PARAM(ctx);
     291    UNUSED_PARAM(object);
     292    UNUSED_PARAM(propertyName);
     293    UNUSED_PARAM(value);
     294
     295    *exception = JSValueMakeNumber(ctx, 1); // distinguish base set from derived set
     296    return true;
     297}
     298
     299static JSValueRef Base_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
     300{
     301    UNUSED_PARAM(ctx);
     302    UNUSED_PARAM(function);
     303    UNUSED_PARAM(thisObject);
     304    UNUSED_PARAM(argumentCount);
     305    UNUSED_PARAM(arguments);
     306   
     307    return JSValueMakeNumber(ctx, 1); // distinguish base call from derived call
     308}
     309
     310static JSStaticFunction Base_staticFunctions[] = {
     311    { "baseProtoDup", NULL, kJSPropertyAttributeNone },
     312    { "baseProto", Base_callAsFunction, kJSPropertyAttributeNone },
     313    { 0, 0, 0 }
     314};
     315
     316static JSStaticValue Base_staticValues[] = {
     317    { "baseDup", Base_get, Base_set, kJSPropertyAttributeNone },
     318    { "baseOnly", Base_get, Base_set, kJSPropertyAttributeNone },
     319    { 0, 0, 0, 0 }
     320};
     321
     322static bool TestInitializeFinalize;
    293323static void Base_initialize(JSContextRef context, JSObjectRef object)
    294324{
    295     assert(!JSObjectGetPrivate(object));
    296     JSObjectSetPrivate(object, (void*)1);
    297 }
    298 
    299 static bool Base_didFinalize;
     325    if (TestInitializeFinalize) {
     326        assert((void*)1 == JSObjectGetPrivate(object));
     327        JSObjectSetPrivate(object, (void*)2);
     328    }
     329}
     330
     331static unsigned Base_didFinalize;
    300332static void Base_finalize(JSObjectRef object)
    301333{
    302     assert((void*)3 == JSObjectGetPrivate(object));
    303     Base_didFinalize = true;
     334    if (TestInitializeFinalize) {
     335        assert((void*)4 == JSObjectGetPrivate(object));
     336        Base_didFinalize = true;
     337    }
    304338}
    305339
     
    308342    static JSClassRef jsClass;
    309343    if (!jsClass) {
    310         JSClassDefinition definition = kJSClassDefinitionNull;
     344        JSClassDefinition definition = kJSClassDefinitionEmpty;
     345        definition.staticValues = Base_staticValues;
     346        definition.staticFunctions = Base_staticFunctions;
    311347        definition.initialize = Base_initialize;
    312348        definition.finalize = Base_finalize;
     
    316352}
    317353
     354static JSValueRef Derived_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
     355{
     356    UNUSED_PARAM(ctx);
     357    UNUSED_PARAM(object);
     358    UNUSED_PARAM(propertyName);
     359
     360    return JSValueMakeNumber(ctx, 2); // distinguish base get form derived get
     361}
     362
     363static bool Derived_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
     364{
     365    UNUSED_PARAM(ctx);
     366    UNUSED_PARAM(object);
     367    UNUSED_PARAM(propertyName);
     368    UNUSED_PARAM(value);
     369
     370    *exception = JSValueMakeNumber(ctx, 2); // distinguish base set from derived set
     371    return true;
     372}
     373
     374static JSValueRef Derived_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
     375{
     376    UNUSED_PARAM(ctx);
     377    UNUSED_PARAM(function);
     378    UNUSED_PARAM(thisObject);
     379    UNUSED_PARAM(argumentCount);
     380    UNUSED_PARAM(arguments);
     381   
     382    return JSValueMakeNumber(ctx, 2); // distinguish base call from derived call
     383}
     384
     385static JSStaticFunction Derived_staticFunctions[] = {
     386    { "protoOnly", Derived_callAsFunction, kJSPropertyAttributeNone },
     387    { "protoDup", NULL, kJSPropertyAttributeNone },
     388    { "baseProtoDup", Derived_callAsFunction, kJSPropertyAttributeNone },
     389    { 0, 0, 0 }
     390};
     391
     392static JSStaticValue Derived_staticValues[] = {
     393    { "derivedOnly", Derived_get, Derived_set, kJSPropertyAttributeNone },
     394    { "protoDup", Derived_get, Derived_set, kJSPropertyAttributeNone },
     395    { "baseDup", Derived_get, Derived_set, kJSPropertyAttributeNone },
     396    { 0, 0, 0, 0 }
     397};
     398
    318399static void Derived_initialize(JSContextRef context, JSObjectRef object)
    319400{
    320     assert((void*)1 == JSObjectGetPrivate(object));
    321     JSObjectSetPrivate(object, (void*)2);
     401    if (TestInitializeFinalize) {
     402        assert((void*)2 == JSObjectGetPrivate(object));
     403        JSObjectSetPrivate(object, (void*)3);
     404    }
    322405}
    323406
    324407static void Derived_finalize(JSObjectRef object)
    325408{
    326     assert((void*)2 == JSObjectGetPrivate(object));
    327     JSObjectSetPrivate(object, (void*)3);
     409    if (TestInitializeFinalize) {
     410        assert((void*)3 == JSObjectGetPrivate(object));
     411        JSObjectSetPrivate(object, (void*)4);
     412    }
    328413}
    329414
     
    332417    static JSClassRef jsClass;
    333418    if (!jsClass) {
    334         JSClassDefinition definition = kJSClassDefinitionNull;
     419        JSClassDefinition definition = kJSClassDefinitionEmpty;
    335420        definition.parentClass = Base_class(context);
     421        definition.staticValues = Derived_staticValues;
     422        definition.staticFunctions = Derived_staticFunctions;
    336423        definition.initialize = Derived_initialize;
    337424        definition.finalize = Derived_finalize;
     
    374461static char* createStringWithContentsOfFile(const char* fileName);
    375462
     463static void testInitializeFinalize()
     464{
     465    JSObjectRef o = JSObjectMake(context, Derived_class(context), (void*)1);
     466    assert(JSObjectGetPrivate(o) == (void*)3);
     467}
     468
    376469int main(int argc, char* argv[])
    377470{
     
    379472    UNUSED_PARAM(argv);
    380473   
     474    // Test garbage collection with a fresh context
     475    context = JSGlobalContextCreate(NULL);
     476    TestInitializeFinalize = true;
     477    testInitializeFinalize();
     478    JSGlobalContextRelease(context);
     479    JSGarbageCollect(context);
     480    TestInitializeFinalize = false;
     481
     482    assert(Base_didFinalize);
     483
    381484    context = JSGlobalContextCreate(NULL);
    382485   
     
    391494    JSValueRef jsOne = JSValueMakeNumber(context, 1);
    392495    JSValueRef jsOneThird = JSValueMakeNumber(context, 1.0 / 3.0);
    393     JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, JSValueMakeNull(context));
     496    JSObjectRef jsObjectNoProto = JSObjectMakeWithPrototype(context, NULL, NULL, JSValueMakeNull(context));
    394497
    395498    // FIXME: test funny utf8 characters
     
    446549
    447550    JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL);
    448     assert(didInitialize);
    449551    JSStringRef myObjectIString = JSStringCreateWithUTF8CString("MyObject");
    450552    JSObjectSetProperty(context, globalObject, myObjectIString, myObject, kJSPropertyAttributeNone, NULL);
     
    660762
    661763    JSStringRef myConstructorIString = JSStringCreateWithUTF8CString("MyConstructor");
    662     JSObjectRef myConstructor = JSObjectMakeConstructorWithCallback(context, NULL, myConstructor_callAsConstructor);
     764    JSObjectRef myConstructor = JSObjectMakeConstructor(context, NULL, myConstructor_callAsConstructor);
    663765    JSObjectSetProperty(context, globalObject, myConstructorIString, myConstructor, kJSPropertyAttributeNone, NULL);
    664766    JSStringRelease(myConstructorIString);
     
    666768    assert(!JSObjectSetPrivate(myConstructor, (void*)1));
    667769    assert(!JSObjectGetPrivate(myConstructor));
     770   
     771    string = JSStringCreateWithUTF8CString("Derived");
     772    JSObjectRef derivedConstructor = JSObjectMakeConstructor(context, Derived_class(context), NULL);
     773    JSObjectSetProperty(context, globalObject, string, derivedConstructor, kJSPropertyAttributeNone, NULL);
     774    JSStringRelease(string);
    668775   
    669776    o = JSObjectMake(context, NULL, NULL);
     
    678785    assert(count == 1); // jsCFString should not be enumerated
    679786
    680     JSClassDefinition nullDefinition = kJSClassDefinitionNull;
     787    JSClassDefinition nullDefinition = kJSClassDefinitionEmpty;
     788    nullDefinition.attributes = kJSClassAttributeNoPrototype;
    681789    JSClassRef nullClass = JSClassCreate(&nullDefinition);
    682790    JSClassRelease(nullClass);
    683791   
     792    nullDefinition = kJSClassDefinitionEmpty;
     793    nullClass = JSClassCreate(&nullDefinition);
     794    JSClassRelease(nullClass);
     795
    684796    functionBody = JSStringCreateWithUTF8CString("return this;");
    685797    function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL);
     
    689801    v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL);
    690802    assert(JSValueIsEqual(context, v, o, NULL));
    691    
    692     o = JSObjectMake(context, Derived_class(context), NULL);
    693     assert(JSObjectGetPrivate(o) == (void*)2);
    694     o = NULL;
    695803   
    696804    char* scriptUTF8 = createStringWithContentsOfFile("testapi.js");
     
    710818    free(scriptUTF8);
    711819
    712     // Allocate a few dummies so that at least one will be collected
    713     JSObjectMake(context, MyObject_class(context), NULL);
    714     JSObjectMake(context, MyObject_class(context), NULL);
    715     JSGarbageCollect(context);
    716     assert(MyObject_didFinalize);
    717     assert(Base_didFinalize);
    718 
    719820    JSStringRelease(jsEmptyIString);
    720821    JSStringRelease(jsOneIString);
     
    729830   
    730831    JSGlobalContextRelease(context);
     832    JSGarbageCollect(context);
     833
    731834    printf("PASS: Program exited normally.\n");
    732835    return 0;
  • trunk/JavaScriptCore/API/testapi.js

    r15473 r15497  
    106106shouldThrow("MyObject.nullCall()");
    107107shouldThrow("MyObject.hasPropertyLie");
     108
     109derived = new Derived();
     110
     111// base properties and functions return 1 when called/gotten; derived, 2
     112shouldBe("derived.baseProtoDup()", 2);
     113shouldBe("derived.baseProto()", 1);
     114shouldBe("derived.baseDup", 2);
     115shouldBe("derived.baseOnly", 1);
     116shouldBe("derived.protoOnly()", 2);
     117shouldBe("derived.protoDup", 2);
     118shouldBe("derived.derivedOnly", 2)
     119
     120// base properties throw 1 when set; derived, 2
     121shouldBe("derived.baseDup = 0", 2);
     122shouldBe("derived.baseOnly = 0", 1);
     123shouldBe("derived.derivedOnly = 0", 2)
     124shouldBe("derived.protoDup = 0", 2);
Note: See TracChangeset for help on using the changeset viewer.