const ClassInfo JSCallbackObject::info = { "CallbackObject", 0, 0, 0 };
-JSCallbackObject::JSCallbackObject(JSContextRef ctx, JSClassRef jsClass)
+JSCallbackObject::JSCallbackObject(ExecState* exec, JSClassRef jsClass)
: JSObject()
{
- init(ctx, jsClass);
+ init(exec, jsClass);
}
-JSCallbackObject::JSCallbackObject(JSContextRef ctx, JSClassRef jsClass, JSValue* prototype)
+JSCallbackObject::JSCallbackObject(ExecState* exec, JSClassRef jsClass, JSValue* prototype)
: JSObject(prototype)
{
- init(ctx, jsClass);
+ init(exec, jsClass);
}
-void JSCallbackObject::init(JSContextRef ctx, JSClassRef jsClass)
+void JSCallbackObject::init(ExecState* exec, JSClassRef jsClass)
{
- ExecState* exec = toJS(ctx);
-
m_privateData = 0;
m_class = JSClassRetain(jsClass);
- JSObjectRef thisRef = toRef(this);
-
+ Vector<JSObjectInitializeCallback, 16> initRoutines;
do {
if (JSObjectInitializeCallback initialize = jsClass->initialize)
- initialize(ctx, thisRef, toRef(exec->exceptionSlot()));
+ initRoutines.append(initialize);
} while ((jsClass = jsClass->parentClass));
+
+ // 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()));
+ }
}
JSCallbackObject::~JSCallbackObject()
class JSCallbackObject : public JSObject
{
public:
- JSCallbackObject(JSContextRef, JSClassRef);
- JSCallbackObject(JSContextRef, JSClassRef, JSValue* prototype);
+ JSCallbackObject(ExecState*, JSClassRef);
+ JSCallbackObject(ExecState*, JSClassRef, JSValue* prototype);
virtual ~JSCallbackObject();
virtual UString className() const;
JSCallbackObject(); // prevent default construction
JSCallbackObject(const JSCallbackObject&);
- void init(JSContextRef, JSClassRef);
+ void init(ExecState*, JSClassRef);
static JSValue* cachedValueGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot&);
static JSValue* staticValueGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot);
{
static JSObjectRef prototype;
if (!prototype) {
- prototype = JSObjectMake(context, JSNodePrototype_class(context), NULL);
+ prototype = JSObjectMake(context, JSNodePrototype_class(context), NULL, NULL);
JSValueProtect(context, prototype);
}
return prototype;
{
Node_ref(node);
- JSObjectRef jsNode = JSObjectMake(context, JSNode_class(context), JSNode_prototype(context));
+ JSObjectRef jsNode = JSObjectMake(context, JSNode_class(context), JSNode_prototype(context), NULL);
JSObjectSetPrivate(jsNode, node);
return jsNode;
}
{
static JSObjectRef prototype;
if (!prototype) {
- prototype = JSObjectMake(context, JSNodeListPrototype_class(context), NULL);
+ prototype = JSObjectMake(context, JSNodeListPrototype_class(context), NULL, NULL);
JSValueProtect(context, prototype);
}
return prototype;
{
NodeList_ref(nodeList);
- JSObjectRef jsNodeList = JSObjectMake(context, JSNodeList_class(context), JSNodeList_prototype(context));
+ JSObjectRef jsNodeList = JSObjectMake(context, JSNodeList_class(context), JSNodeList_prototype(context), NULL);
JSObjectSetPrivate(jsNodeList, nodeList);
return jsNodeList;
}
delete jsClass;
}
-JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype)
+JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype, JSValueRef* exception)
{
JSLock lock;
if (!prototype)
jsPrototype = exec->lexicalInterpreter()->builtinObjectPrototype();
- if (!jsClass)
- return toRef(new JSObject(jsPrototype)); // slightly more efficient
- else
- return toRef(new JSCallbackObject(ctx, jsClass, jsPrototype));
+ 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;
}
JSObjectRef JSObjectMakeFunctionWithCallback(JSContextRef ctx, JSStringRef name, JSObjectCallAsFunctionCallback callAsFunction)
@discussion If you named your function Initialize, you would declare it like this:
void Initialize(JSContextRef ctx, JSObjectRef object, JSValueRef* exception);
+
+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);
@discussion If you named your function Finalize, you would declare it like this:
void Finalize(JSObjectRef object);
+
+The finalize callback is called on the most derived class first, and the least
+derived class (the parent class) last.
*/
typedef void
(*JSObjectFinalizeCallback) (JSObjectRef object);
@param possibleInstance The JSValue being tested to determine if it is an instance of constructor.
@param exception A pointer to a JSValueRef in which to return an exception, if any.
@result true if possibleInstance is an instance of constructor, otherwise false.
-
@discussion If you named your function HasInstance, you would declare it like this:
bool HasInstance(JSContextRef ctx, JSObjectRef constructor, JSValueRef possibleInstance, JSValueRef* exception);
@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 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.
*/
-JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype);
+JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype, JSValueRef* exception);
/*!
@function
return NULL;
}
-static bool didFinalize = false;
+static bool MyObject_didFinalize = false;
static void MyObject_finalize(JSObjectRef object)
{
UNUSED_PARAM(context);
UNUSED_PARAM(object);
- didFinalize = true;
+ MyObject_didFinalize = true;
}
static JSStaticValue evilStaticValues[] = {
return jsClass;
}
+static void Base_initialize(JSContextRef context, JSObjectRef object, JSValueRef* exception)
+{
+ assert(!JSObjectGetPrivate(object));
+ JSObjectSetPrivate(object, (void*)1);
+}
+
+static bool Base_didFinalize;
+static void Base_finalize(JSObjectRef object)
+{
+ assert((void*)3 == JSObjectGetPrivate(object));
+ Base_didFinalize = true;
+}
+
+static JSClassRef Base_class(JSContextRef context)
+{
+ static JSClassRef jsClass;
+ if (!jsClass) {
+ JSClassDefinition definition = kJSClassDefinitionNull;
+ definition.initialize = Base_initialize;
+ definition.finalize = Base_finalize;
+ jsClass = JSClassCreate(&definition);
+ }
+ return jsClass;
+}
+
+static void Derived_initialize(JSContextRef context, JSObjectRef object, JSValueRef* exception)
+{
+ assert((void*)1 == JSObjectGetPrivate(object));
+ JSObjectSetPrivate(object, (void*)2);
+}
+
+static void Derived_finalize(JSObjectRef object)
+{
+ assert((void*)2 == JSObjectGetPrivate(object));
+ JSObjectSetPrivate(object, (void*)3);
+}
+
+static JSClassRef Derived_class(JSContextRef context)
+{
+ static JSClassRef jsClass;
+ if (!jsClass) {
+ JSClassDefinition definition = kJSClassDefinitionNull;
+ definition.parentClass = Base_class(context);
+ definition.initialize = Derived_initialize;
+ definition.finalize = Derived_finalize;
+ jsClass = JSClassCreate(&definition);
+ }
+ return jsClass;
+}
+
static JSValueRef print_callAsFunction(JSContextRef context, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
UNUSED_PARAM(functionObject);
{
UNUSED_PARAM(constructorObject);
- JSObjectRef result = JSObjectMake(context, NULL, 0);
+ JSObjectRef result = JSObjectMake(context, NULL, 0, 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));
+ JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, JSValueMakeNull(context), NULL);
// FIXME: test funny utf8 characters
JSStringRef jsEmptyIString = JSStringCreateWithUTF8CString("");
assert(JSValueGetType(context, jsCFEmptyStringWithCharacters) == kJSTypeString);
#endif // __APPLE__
- JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL);
+ JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL, NULL);
assert(didInitialize);
JSStringRef myObjectIString = JSStringCreateWithUTF8CString("MyObject");
JSObjectSetProperty(context, globalObject, myObjectIString, myObject, kJSPropertyAttributeNone, NULL);
CFRelease(cfEmptyString);
#endif // __APPLE__
- jsGlobalValue = JSObjectMake(context, NULL, NULL);
+ jsGlobalValue = JSObjectMake(context, NULL, NULL, NULL);
JSValueProtect(context, jsGlobalValue);
JSGarbageCollect(context);
assert(JSValueIsObject(context, jsGlobalValue));
assert(!JSObjectSetPrivate(myConstructor, (void*)1));
assert(!JSObjectGetPrivate(myConstructor));
- o = JSObjectMake(context, NULL, NULL);
+ o = JSObjectMake(context, NULL, 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);
+ assert(JSObjectGetPrivate(o) == (void*)2);
+ o = NULL;
char* scriptUTF8 = createStringWithContentsOfFile("testapi.js");
JSStringRef script = JSStringCreateWithUTF8CString(scriptUTF8);
free(scriptUTF8);
// Allocate a few dummies so that at least one will be collected
- JSObjectMake(context, MyObject_class(context), 0);
- JSObjectMake(context, MyObject_class(context), 0);
+ JSObjectMake(context, MyObject_class(context), NULL, NULL);
+ JSObjectMake(context, MyObject_class(context), NULL, NULL);
JSGarbageCollect(context);
- assert(didFinalize);
+ assert(MyObject_didFinalize);
+ assert(Base_didFinalize);
JSStringRelease(jsEmptyIString);
JSStringRelease(jsOneIString);
+2006-07-17 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Maciej.
+
+ - Changed the initialize callback to run from least derived class (parent
+ class) to most derived class. This enables C++ style initialization,
+ and derived class overriding of member data.
+
+ - Added excpetion propopgation to JSObjectMake, to support initialize
+ exceptions, and generally round out our policy of making function
+ signatures as long as possible.
+
+ * API/JSCallbackObject.h: Use ExecState instead of ContextRef, cuz we're
+ in C++ land now.
+
2006-07-17 Geoffrey Garen <ggaren@apple.com>
Reviewed by Maciej.