const ClassInfo JSCallbackObject::info = { "CallbackObject", 0, 0, 0 };
-JSCallbackObject::JSCallbackObject(ExecState* exec, JSClassRef jsClass)
- : JSObject()
-{
- init(exec, jsClass);
-}
-
-JSCallbackObject::JSCallbackObject(ExecState* exec, JSClassRef jsClass, JSValue* prototype)
+JSCallbackObject::JSCallbackObject(ExecState* exec, JSClassRef jsClass, JSValue* prototype, void* data)
: JSObject(prototype)
{
- init(exec, jsClass);
+ init(exec, jsClass, data);
}
-void JSCallbackObject::init(ExecState* exec, JSClassRef jsClass)
+void JSCallbackObject::init(ExecState* exec, JSClassRef jsClass, void* data)
{
- m_privateData = 0;
+ m_privateData = data;
m_class = JSClassRetain(jsClass);
Vector<JSObjectInitializeCallback, 16> initRoutines;
// initialize from base to derived
for (int i = initRoutines.size() - 1; i >= 0; i--) {
JSObjectInitializeCallback initialize = initRoutines[i];
- initialize(toRef(exec), toRef(this), toRef(exec->exceptionSlot()));
+ initialize(toRef(exec), toRef(this));
}
}
class JSCallbackObject : public JSObject
{
public:
- JSCallbackObject(ExecState*, JSClassRef);
- JSCallbackObject(ExecState*, JSClassRef, JSValue* prototype);
+ JSCallbackObject(ExecState*, JSClassRef, JSValue* prototype, void* data);
virtual ~JSCallbackObject();
virtual UString className() const;
JSCallbackObject(); // prevent default construction
JSCallbackObject(const JSCallbackObject&);
- void init(ExecState*, JSClassRef);
+ void init(ExecState*, JSClassRef jsClass, void*);
static JSValue* cachedValueGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot&);
static JSValue* staticValueGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot);
JSObject* globalObject;
if (globalObjectClass)
// FIXME: We need to pass a real ExecState here to support an initialize callback in globalObjectClass
- globalObject = new JSCallbackObject(0, globalObjectClass);
+ globalObject = new JSCallbackObject(0, globalObjectClass, 0, 0);
else
globalObject = new JSObject();
{ 0, 0, 0, 0 }
};
+static void JSNode_initialize(JSContextRef context, JSObjectRef object)
+{
+ Node* node = JSObjectGetPrivate(object);
+ assert(node);
+
+ Node_ref(node);
+}
+
static void JSNode_finalize(JSObjectRef object)
{
Node* node = JSObjectGetPrivate(object);
if (!jsClass) {
JSClassDefinition definition = kJSClassDefinitionNull;
definition.staticValues = JSNode_staticValues;
+ definition.initialize = JSNode_initialize;
definition.finalize = JSNode_finalize;
jsClass = JSClassCreate(&definition);
{
static JSObjectRef prototype;
if (!prototype) {
- prototype = JSObjectMake(context, JSNodePrototype_class(context), NULL, NULL);
+ prototype = JSObjectMake(context, JSNodePrototype_class(context), NULL);
JSValueProtect(context, prototype);
}
return prototype;
JSObjectRef JSNode_new(JSContextRef context, Node* node)
{
- Node_ref(node);
-
- JSObjectRef jsNode = JSObjectMake(context, JSNode_class(context), JSNode_prototype(context), NULL);
- JSObjectSetPrivate(jsNode, node);
- return jsNode;
+ return JSObjectMakeWithData(context, JSNode_class(context), JSNode_prototype(context), node);
}
JSObjectRef JSNode_construct(JSContextRef context, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
return NULL;
}
+static void JSNodeList_initialize(JSContextRef context, JSObjectRef thisObject)
+{
+ NodeList* nodeList = JSObjectGetPrivate(thisObject);
+ assert(nodeList);
+
+ NodeList_ref(nodeList);
+}
+
static void JSNodeList_finalize(JSObjectRef thisObject)
{
NodeList* nodeList = JSObjectGetPrivate(thisObject);
assert(nodeList);
+
NodeList_deref(nodeList);
}
JSClassDefinition definition = kJSClassDefinitionNull;
definition.staticValues = JSNodeList_staticValues;
definition.getProperty = JSNodeList_getProperty;
+ definition.initialize = JSNodeList_initialize;
definition.finalize = JSNodeList_finalize;
jsClass = JSClassCreate(&definition);
{
static JSObjectRef prototype;
if (!prototype) {
- prototype = JSObjectMake(context, JSNodeListPrototype_class(context), NULL, NULL);
+ prototype = JSObjectMake(context, JSNodeListPrototype_class(context), NULL);
JSValueProtect(context, prototype);
}
return prototype;
JSObjectRef JSNodeList_new(JSContextRef context, NodeList* nodeList)
{
- NodeList_ref(nodeList);
-
- JSObjectRef jsNodeList = JSObjectMake(context, JSNodeList_class(context), JSNodeList_prototype(context), NULL);
- JSObjectSetPrivate(jsNodeList, nodeList);
- return jsNodeList;
+ return JSObjectMakeWithData(context, JSNodeList_class(context), JSNodeList_prototype(context), nodeList);
}
delete jsClass;
}
-JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype, JSValueRef* exception)
+JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype)
+{
+ return JSObjectMakeWithData(ctx, jsClass, prototype, 0);
+}
+
+JSObjectRef JSObjectMakeWithData(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype, void* data)
{
JSLock lock;
if (!prototype)
jsPrototype = exec->lexicalInterpreter()->builtinObjectPrototype();
- JSObjectRef result;
- if (jsClass) {
- result = toRef(new JSCallbackObject(exec, jsClass, jsPrototype));
- if (exec->hadException()) {
- if (exception)
- *exception = toRef(exec->exception());
- exec->clearException();
- }
- } else
- result = toRef(new JSObject(jsPrototype)); // slightly more efficient -- and can't throw
-
- return result;
+ if (!jsClass)
+ return toRef(new JSObject(jsPrototype)); // slightly more efficient
+
+ return toRef(new JSCallbackObject(exec, jsClass, jsPrototype, data)); // initialize can't throw
}
JSObjectRef JSObjectMakeFunctionWithCallback(JSContextRef ctx, JSStringRef name, JSObjectCallAsFunctionCallback callAsFunction)
@abstract The callback invoked when an object is first created.
@param ctx The execution context to use.
@param object The JSObject being created.
-@param exception A pointer to a JSValueRef in which to return an exception, if any.
@discussion If you named your function Initialize, you would declare it like this:
-void Initialize(JSContextRef ctx, JSObjectRef object, JSValueRef* exception);
+void Initialize(JSContextRef ctx, JSObjectRef object);
Unlike the other object callbacks, the initialize callback is called on the least
derived class (the parent class) first, and the most derived class last.
*/
typedef void
-(*JSObjectInitializeCallback) (JSContextRef ctx, JSObjectRef object, JSValueRef* exception);
+(*JSObjectInitializeCallback) (JSContextRef ctx, JSObjectRef object);
/*!
@typedef JSObjectFinalizeCallback
/*!
@function
-@abstract Creates a JavaScript object with a given class and prototype.
+@abstract Creates a JavaScript object.
+@param ctx The execution context to use.
+@param jsClass The JSClass to assign to the object. Pass NULL to use the default object class.
+@param prototype The prototype to assign to the object. Pass NULL to use the default object prototype.
+@result A JSObject with the given class, prototype, and private data.
+@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.
+*/
+JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype);
+
+/*!
+@function
+@abstract Creates a JavaScript object.
@param ctx The execution context to use.
@param jsClass The JSClass to assign to the object. Pass NULL to use the default object class.
@param prototype The prototype to assign to the object. Pass NULL to use the default object prototype.
+@param data A void* to set as the object's private data. Pass NULL to specify no private data.
@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.
-@result A JSObject with the given class and prototype.
+@result A JSObject with the given class, prototype, and private data.
+@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.
+
+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.
*/
-JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype, JSValueRef* exception);
+JSObjectRef JSObjectMakeWithData(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype, void* data);
/*!
@function
/*!
@function
-@abstract Gets a pointer to private data from an object.
+@abstract Gets an object's private data.
@param object A JSObject whose private data you want to get.
-@result A void* that points to the object's private data, if the object has private data, otherwise NULL.
+@result A void* that is the object's private data, if the object has private data, otherwise NULL.
*/
void* JSObjectGetPrivate(JSObjectRef object);
@function
@abstract Sets a pointer to private data on an object.
@param object A JSObject whose private data you want to set.
-@param data A void* that points to the object's private data.
+@param data A void* to set as the object's private data.
@result true if the object can store private data, otherwise false.
-@discussion Only custom objects created with a JSClass can store private data.
+@discussion The default object class does not allocate storage for private data. Only objects created with a non-NULL JSClass can store private data.
*/
bool JSObjectSetPrivate(JSObjectRef object, void* data);
JSStringRelease(script);
free(scriptUTF8);
-#if 0 // used for leak/finalize debugging
- int i;
- for (i = 0; i < 1000; i++) {
- JSObjectRef o = JSObjectMake(context, NULL, NULL);
- (void)o;
- }
- JSGarbageCollect();
-#endif
-
+ globalObject = 0;
JSGlobalContextRelease(context);
+ JSGarbageCollect(context);
printf("PASS: Program exited normally.\n");
return 0;
}
node.appendChild(child1);
node.appendChild(child2);
- for (var i = 0; i < node.childNodes.length + 1; i++) {
- print("item " + i + ": " + node.childNodes.item(i));
+ var childNodes = node.childNodes;
+
+ for (var i = 0; i < childNodes.length + 1; i++) {
+ print("item " + i + ": " + childNodes.item(i));
}
- for (var i = 0; i < node.childNodes.length + 1; i++) {
- print(i + ": " + node.childNodes[i]);
+ for (var i = 0; i < childNodes.length + 1; i++) {
+ print(i + ": " + childNodes[i]);
}
node.removeChild(child1);
node.replaceChild(child3, child2);
- for (var i = 0; i < node.childNodes.length + 1; i++) {
- print("item " + i + ": " + node.childNodes.item(i));
+ for (var i = 0; i < childNodes.length + 1; i++) {
+ print("item " + i + ": " + childNodes.item(i));
}
- for (var i = 0; i < node.childNodes.length + 1; i++) {
- print(i + ": " + node.childNodes[i]);
+ for (var i = 0; i < childNodes.length + 1; i++) {
+ print(i + ": " + childNodes[i]);
}
try {
/* MyObject pseudo-class */
static bool didInitialize = false;
-static void MyObject_initialize(JSContextRef context, JSObjectRef object, JSValueRef* exception)
+static void MyObject_initialize(JSContextRef context, JSObjectRef object)
{
UNUSED_PARAM(context);
UNUSED_PARAM(object);
return jsClass;
}
-static void Base_initialize(JSContextRef context, JSObjectRef object, JSValueRef* exception)
+static void Base_initialize(JSContextRef context, JSObjectRef object)
{
assert(!JSObjectGetPrivate(object));
JSObjectSetPrivate(object, (void*)1);
return jsClass;
}
-static void Derived_initialize(JSContextRef context, JSObjectRef object, JSValueRef* exception)
+static void Derived_initialize(JSContextRef context, JSObjectRef object)
{
assert((void*)1 == JSObjectGetPrivate(object));
JSObjectSetPrivate(object, (void*)2);
{
UNUSED_PARAM(constructorObject);
- JSObjectRef result = JSObjectMake(context, NULL, 0, NULL);
+ JSObjectRef result = JSObjectMake(context, NULL, NULL);
if (argumentCount > 0) {
JSStringRef value = JSStringCreateWithUTF8CString("value");
JSObjectSetProperty(context, result, value, arguments[0], kJSPropertyAttributeNone, NULL);
JSValueRef jsZero = JSValueMakeNumber(context, 0);
JSValueRef jsOne = JSValueMakeNumber(context, 1);
JSValueRef jsOneThird = JSValueMakeNumber(context, 1.0 / 3.0);
- JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, JSValueMakeNull(context), NULL);
+ JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, JSValueMakeNull(context));
// FIXME: test funny utf8 characters
JSStringRef jsEmptyIString = JSStringCreateWithUTF8CString("");
assert(JSValueGetType(context, jsCFEmptyStringWithCharacters) == kJSTypeString);
#endif // __APPLE__
- JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL, NULL);
+ JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL);
assert(didInitialize);
JSStringRef myObjectIString = JSStringCreateWithUTF8CString("MyObject");
JSObjectSetProperty(context, globalObject, myObjectIString, myObject, kJSPropertyAttributeNone, NULL);
CFRelease(cfEmptyString);
#endif // __APPLE__
- jsGlobalValue = JSObjectMake(context, NULL, NULL, NULL);
+ jsGlobalValue = JSObjectMake(context, NULL, NULL);
JSValueProtect(context, jsGlobalValue);
JSGarbageCollect(context);
assert(JSValueIsObject(context, jsGlobalValue));
assert(!JSObjectSetPrivate(myConstructor, (void*)1));
assert(!JSObjectGetPrivate(myConstructor));
- o = JSObjectMake(context, NULL, NULL, NULL);
+ o = JSObjectMake(context, NULL, NULL);
JSObjectSetProperty(context, o, jsOneIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeNone, NULL);
JSObjectSetProperty(context, o, jsCFIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeDontEnum, NULL);
JSPropertyNameArrayRef nameArray = JSObjectCopyPropertyNames(context, o);
v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL);
assert(JSValueIsEqual(context, v, o, NULL));
- exception = NULL;
- o = JSObjectMake(context, Derived_class(context), NULL, &exception);
- assert(!exception);
+ o = JSObjectMake(context, Derived_class(context), NULL);
assert(JSObjectGetPrivate(o) == (void*)2);
o = NULL;
free(scriptUTF8);
// Allocate a few dummies so that at least one will be collected
- JSObjectMake(context, MyObject_class(context), NULL, NULL);
- JSObjectMake(context, MyObject_class(context), NULL, NULL);
+ JSObjectMake(context, MyObject_class(context), NULL);
+ JSObjectMake(context, MyObject_class(context), NULL);
JSGarbageCollect(context);
assert(MyObject_didFinalize);
assert(Base_didFinalize);
+2006-07-17 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Maciej.
+
+ - Removed the exception parameter from the initialize callback and, by extension,
+ JSObjectMake. We have never had a need for exceptions when iniitializing,
+ so the parameter seemed likely to "get in the way."
+
+ Also, an exception in JavaScript is thrown in response to input --
+ "invalid URL", "index not a number", etc., so it's the job of the
+ constructor function, not the initialize method, to throw.
+
+ If initialize *really* wants to throw, it can communicate the throw to
+ the constructor through the constructed object's private data (e.g., set
+ it to NULL, signaling to the consntructor that initialization failed.)
+
+ - Added JSObjectMakeWithData, which enables a constructor to set private
+ data on an object *before* it has been initialized. That way, the initialize
+ methods can properly operate on the data.
+
+ * API/JSNode.c: Moved ref into the initialize method, for better encapsulation,
+ now that it's possible.
+ * API/JSNodeList.c: ditto
+ * API/minidom.c:
+ (main): Do more aggressive garbage collection to test ref/deref and
+ initialize/finalize.
+ * API/minidom.js: store childNodes in a temporary so it doesn't get re-created
+ like a thousand times. This makes debugging ref/deref easier
+
2006-07-17 Geoffrey Garen <ggaren@apple.com>
Reviewed by Maciej.
_JSObjectMakeConstructorWithCallback
_JSObjectMakeFunctionWithCallback
_JSObjectMakeFunction
+_JSObjectMakeWithData
_JSObjectSetPrivate
_JSObjectSetProperty
_JSObjectSetPropertyAtIndex