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.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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}
Note: See TracChangeset for help on using the changeset viewer.