Reviewed by Maciej.
authorggaren <ggaren@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 17 Jul 2006 08:20:28 +0000 (08:20 +0000)
committerggaren <ggaren@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 17 Jul 2006 08:20:28 +0000 (08:20 +0000)
        - Changed JSObjectMakeConstructor to JSObjectMakeConstructorWithCallback,
        to match JSObjectMakeFunctionWithCallback.

        - Added prototype parameter, so the generated constructor
        automatically works with hasInstance / instanceof

        - Moved hasInstance implementation from InternalFunctionImp to JSObject
        so that subclasses can inherit it without inheriting function-related baggage.
        More refactoring here would be good, but this seems like a good short-term
        solution.

        (KJS::JSCallbackFunction::implementsHasInstance): override and return false,
        because callback functions aren't constructors.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@15482 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
JavaScriptCore/API/JSCallbackConstructor.cpp
JavaScriptCore/API/JSCallbackConstructor.h
JavaScriptCore/API/JSCallbackFunction.cpp
JavaScriptCore/API/JSCallbackFunction.h
JavaScriptCore/API/JSNode.c
JavaScriptCore/API/JSNode.h
JavaScriptCore/API/JSObjectRef.cpp
JavaScriptCore/API/JSObjectRef.h
JavaScriptCore/API/minidom.c
JavaScriptCore/API/minidom.js
JavaScriptCore/API/testapi.c
JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.exp
JavaScriptCore/kjs/internal.cpp
JavaScriptCore/kjs/internal.h
JavaScriptCore/kjs/object.cpp

index 49a560d37cbf54cc749aba0cc900cef670d7f9ac..28557e74b872d5893ee9d52f79c302a4b19ce991 100644 (file)
@@ -37,6 +37,11 @@ JSCallbackConstructor::JSCallbackConstructor(ExecState* exec, JSObjectCallAsCons
 {
 }
 
+bool JSCallbackConstructor::implementsHasInstance() const
+{
+    return true;
+}
+
 bool JSCallbackConstructor::implementsConstruct() const
 {
     return true;
index 7f32229e648e6d19751f7afe7d7927be0c73dca6..32dd3062372f70b60db09987921c7c2cb1fe518c 100644 (file)
 #define JSCallbackConstructor_h
 
 #include "JSObjectRef.h"
-#include "object.h"
+#include <kjs/object.h>
 
 namespace KJS {
-    
+
 class JSCallbackConstructor : public JSObject
 {
 public:
     JSCallbackConstructor(ExecState* exec, JSObjectCallAsConstructorCallback callback);
     
+    virtual bool implementsHasInstance() const;
+    
     virtual bool implementsConstruct() const;
     virtual JSObject* construct(ExecState*, const List &args);
-
+    
     virtual const ClassInfo *classInfo() const { return &info; }
     static const ClassInfo info;
     
index 7062f9cfec8e9d88e946a02b484c1e5a66961be1..0f9e4c1ee9cce15126cd881239cc2d9e7cf94cb5 100644 (file)
@@ -39,6 +39,12 @@ JSCallbackFunction::JSCallbackFunction(ExecState* exec, JSObjectCallAsFunctionCa
 {
 }
 
+// InternalFunctionImp mish-mashes constructor and function behavior -- we should 
+// refactor the code so this override isn't necessary
+bool JSCallbackFunction::implementsHasInstance() const { 
+    return false; 
+}
+
 JSValue* JSCallbackFunction::callAsFunction(ExecState* exec, JSObject* thisObj, const List &args)
 {
     JSContextRef execRef = toRef(exec);
index 72dded45b127a185a553f1abff8bb02c2e8310f5..302b4e370abfc9702ab8aa6f284b6793baf5b65e 100644 (file)
@@ -38,6 +38,7 @@ class JSCallbackFunction : public InternalFunctionImp
 public:
     JSCallbackFunction(ExecState* exec, JSObjectCallAsFunctionCallback callback, const Identifier& name);
 
+    virtual bool implementsHasInstance() const;
     virtual JSValue* callAsFunction(ExecState*, JSObject* thisObj, const List &args);
 
     virtual const ClassInfo *classInfo() const { return &info; }
index ad2c07e1b60136274d43de697527822256b20e0f..a7b5635194c7e03d1d38d52509da679e3c4107a6 100644 (file)
@@ -177,7 +177,7 @@ static JSClassRef JSNode_class(JSContextRef context)
     return jsClass;
 }
 
-static JSObjectRef JSNode_prototype(JSContextRef context)
+JSObjectRef JSNode_prototype(JSContextRef context)
 {
     static JSObjectRef prototype;
     if (!prototype) {
index a0ba890db2ea6c0a6d69ddc4a2175cc0253d8bf9..38ab0e53a4e89dadd61ffd3b2b69a9b69a4a21b1 100644 (file)
@@ -31,6 +31,7 @@
 #include "Node.h"
 
 extern JSObjectRef JSNode_new(JSContextRef context, Node* node);
+extern JSObjectRef JSNode_prototype(JSContextRef context);
 extern JSObjectRef JSNode_construct(JSContextRef context, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
 
 #endif // JSNode_h
index 686363201a62c324afb0d5e9c82e4b36e71a07ab..99f2f992c999c71a8db7dddd73eaf889b6e33063 100644 (file)
@@ -84,11 +84,18 @@ JSObjectRef JSObjectMakeFunctionWithCallback(JSContextRef ctx, JSStringRef name,
     return toRef(new JSCallbackFunction(exec, callAsFunction, nameID));
 }
 
-JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSObjectCallAsConstructorCallback callAsConstructor)
+JSObjectRef JSObjectMakeConstructorWithCallback(JSContextRef ctx, JSValueRef prototype, JSObjectCallAsConstructorCallback callAsConstructor)
 {
     JSLock lock;
     ExecState* exec = toJS(ctx);
-    return toRef(new JSCallbackConstructor(exec, callAsConstructor));
+    JSValue* jsPrototype = toJS(prototype);
+    
+    if (!jsPrototype)
+        jsPrototype = exec->dynamicInterpreter()->builtinObjectPrototype();
+    
+    JSObject* constructor = new JSCallbackConstructor(exec, callAsConstructor);
+    constructor->put(exec, prototypePropertyName, jsPrototype, DontEnum|DontDelete|ReadOnly);
+    return toRef(constructor);
 }
 
 JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned parameterCount, const JSStringRef parameterNames[], JSStringRef body, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception)
index 5f3ed025b0175a06b29c2d555e8b30338403b121..36a8820e1cbf73b39a4961183bd7cd60cac6de00 100644 (file)
@@ -388,17 +388,19 @@ JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, JSValueRef protot
 @param ctx The execution context to use.
 @param name A JSString containing the function's name. This will be used when converting the function to string. Pass NULL to create an anonymous function.
 @param callAsFunction The JSObjectCallAsFunctionCallback to invoke when the function is called.
-@result A JSObject that is an anonymous function. The object's prototype will be the default function prototype.
+@result A JSObject that is a function. The object's prototype will be the default function prototype.
 */
 JSObjectRef JSObjectMakeFunctionWithCallback(JSContextRef ctx, JSStringRef name, JSObjectCallAsFunctionCallback callAsFunction);
+
 /*!
 @function
 @abstract Convenience method for creating a JavaScript constructor with a given callback as its implementation.
 @param ctx The execution context to use.
+@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.
 @param callAsConstructor The JSObjectCallAsConstructorCallback to invoke when the constructor is used in a 'new' expression.
 @result A JSObject that is a constructor. The object's prototype will be the default object prototype.
 */
-JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSObjectCallAsConstructorCallback callAsConstructor);
+JSObjectRef JSObjectMakeConstructorWithCallback(JSContextRef ctx, JSValueRef prototype, JSObjectCallAsConstructorCallback callAsConstructor);
 
 /*!
 @function
index fc3f9c66e651f99e951b8af5012e44f764b871fe..7ce08fe9e2faa7366d8080cdd80f8783261d3869 100644 (file)
@@ -44,7 +44,7 @@ int main(int argc, char* argv[])
     JSStringRelease(printIString);
     
     JSStringRef node = JSStringCreateWithUTF8CString("Node");
-    JSObjectSetProperty(context, globalObject, node, JSObjectMakeConstructor(context, JSNode_construct), kJSPropertyAttributeNone, NULL);
+    JSObjectSetProperty(context, globalObject, node, JSObjectMakeConstructorWithCallback(context, JSNode_prototype(context), JSNode_construct), kJSPropertyAttributeNone, NULL);
     JSStringRelease(node);
     
     char* scriptUTF8 = createStringWithContentsOfFile("minidom.js");
index 4a817a05196f02b70dfb846d163fe29cb846b008..a68da9401da6515534d44c2e34fd4ca06eaf7355 100644 (file)
@@ -240,6 +240,11 @@ function test()
     oldNodeType = node.nodeType;
     node.nodeType = 1;
     shouldBe("node.nodeType", oldNodeType);
+    
+    shouldBe("node instanceof Node", true);
+    shouldBe("new Object() instanceof Node", false);
+    
+    print(Node);
 
     /*
     var element, name, weapon;
index 598378072d1684e16bad75e14f02bc8653517679..9f5a73ff939fbaf3dd47e6462e67a2cbd9b0be81 100644 (file)
@@ -609,7 +609,7 @@ int main(int argc, char* argv[])
     assert(!JSObjectGetPrivate(printFunction));
 
     JSStringRef myConstructorIString = JSStringCreateWithUTF8CString("MyConstructor");
-    JSObjectRef myConstructor = JSObjectMakeConstructor(context, myConstructor_callAsConstructor);
+    JSObjectRef myConstructor = JSObjectMakeConstructorWithCallback(context, NULL, myConstructor_callAsConstructor);
     JSObjectSetProperty(context, globalObject, myConstructorIString, myConstructor, kJSPropertyAttributeNone, NULL);
     JSStringRelease(myConstructorIString);
     
index 30e18bf798a0cf578e7a5d50cc1aa133c4bf9108..a32650aee562117b39b8173b368820f2dfe5920c 100644 (file)
@@ -1,3 +1,21 @@
+2006-07-17  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Maciej.
+        
+        - Changed JSObjectMakeConstructor to JSObjectMakeConstructorWithCallback,
+        to match JSObjectMakeFunctionWithCallback.
+        
+        - Added prototype parameter, so the generated constructor
+        automatically works with hasInstance / instanceof
+        
+        - Moved hasInstance implementation from InternalFunctionImp to JSObject
+        so that subclasses can inherit it without inheriting function-related baggage.
+        More refactoring here would be good, but this seems like a good short-term
+        solution.
+
+        (KJS::JSCallbackFunction::implementsHasInstance): override and return false,
+        because callback functions aren't constructors.
+
 2006-07-17  Maciej Stachowiak  <mjs@apple.com>
 
         Reviewed by Geoff.
index 1032d9ab054799d35a10de6e496468101ef36072..3570a326413182ac7fdf3ddcf24f8321bf2df8f6 100644 (file)
@@ -23,7 +23,7 @@ _JSObjectHasProperty
 _JSObjectIsConstructor
 _JSObjectIsFunction
 _JSObjectMake
-_JSObjectMakeConstructor
+_JSObjectMakeConstructorWithCallback
 _JSObjectMakeFunctionWithCallback
 _JSObjectMakeFunction
 _JSObjectSetPrivate
@@ -148,7 +148,6 @@ __ZN3KJS15SavedPropertiesD1Ev
 __ZN3KJS16RuntimeObjectImpC1EPNS_8Bindings8InstanceE
 __ZN3KJS17PropertyNameArray3addERKNS_10IdentifierE
 __ZN3KJS18lengthPropertyNameE
-__ZN3KJS19InternalFunctionImp11hasInstanceEPNS_9ExecStateEPNS_7JSValueE
 __ZN3KJS19InternalFunctionImp4infoE
 __ZN3KJS19InternalFunctionImpC2EPNS_17FunctionPrototypeERKNS_10IdentifierE
 __ZN3KJS19messagePropertyNameE
index b4ac913b202cf771128ecd0a7ea51e203e97351f..5ef030e8631bbb0f5320ad317fdc6e9d18f94390 100644 (file)
@@ -216,25 +216,6 @@ bool InternalFunctionImp::implementsHasInstance() const
   return true;
 }
 
-bool InternalFunctionImp::hasInstance(ExecState *exec, JSValue *value)
-{
-  if (!value->isObject())
-    return false;
-
-  JSValue *prot = get(exec,prototypePropertyName);
-  if (!prot->isObject() && !prot->isNull()) {
-    throwError(exec, TypeError, "Invalid prototype encountered in instanceof operation.");
-    return false;
-  }
-
-  JSObject *v = static_cast<JSObject *>(value);
-  while ((v = v->prototype()->getObject())) {
-    if (v == prot)
-      return true;
-  }
-  return false;
-}
-
 // ------------------------------ global functions -----------------------------
 
 double roundValue(ExecState *exec, JSValue *v)
index a8d4e2e085a404b701acd8230b7deee53fa59e44..79250efef36b6d1bce7fe4907bd93d7d46bcdc20 100644 (file)
@@ -154,7 +154,6 @@ namespace KJS {
     virtual bool implementsCall() const;
     virtual JSValue* callAsFunction(ExecState*, JSObject* thisObjec, const List& args) = 0;
     virtual bool implementsHasInstance() const;
-    virtual bool hasInstance(ExecState*, JSValue*);
 
     virtual const ClassInfo* classInfo() const { return &info; }
     static const ClassInfo info;
index 0e0649f1342b05f5bda73764fee40d05410b0c64..a28fc269516282e386954c1eaa8e29ca1ff60e9f 100644 (file)
@@ -444,10 +444,23 @@ bool JSObject::implementsHasInstance() const
   return false;
 }
 
-bool JSObject::hasInstance(ExecState *, JSValue *)
+bool JSObject::hasInstance(ExecState* exec, JSValue* value)
 {
-  assert(false);
-  return false;
+    JSValue* proto = get(exec, prototypePropertyName);
+    if (!proto->isObject()) {
+        throwError(exec, TypeError, "intanceof called on an object with an invalid prototype property.");
+        return false;
+    }
+    
+    if (!value->isObject())
+        return false;
+    
+    JSObject* o = static_cast<JSObject*>(value);
+    while ((o = o->prototype()->getObject())) {
+        if (o == proto)
+            return true;
+    }
+    return false;
 }
 
 bool JSObject::propertyIsEnumerable(ExecState*, const Identifier& propertyName) const