Author: [EMAIL PROTECTED]
Date: Thu Sep 25 00:38:37 2008
New Revision: 3680

Modified:
    changes/jat/oophm-branch/plugins/xpcom/FFSessionHandler.cpp
    changes/jat/oophm-branch/plugins/xpcom/JavaObject.cpp

Log:
Checkpoint XPCOM plugin that completely passes HostedTest, including  
toString.

There are still some issues to resolve:
  1) freeing Java values is disabled, because the JavaObject wrapper can get
     finalized after the session is disconnected, in which case it points to
     invalid data.
  2) when running a long stream of tests, I get a weird crash just trying to
     convert a value to a string for debugging.  Even with firefox debug  
symbols
     loaded, without a debug compile it is hard to tell what is going wrong  
as
     the optimization hampers debugging.
  3) the argument stack could be improved, and tied into a fix for #1 above.

However, I think the general outline is close enough that people can start
taking a look at it to go into branches/oophm.


Modified: changes/jat/oophm-branch/plugins/xpcom/FFSessionHandler.cpp
==============================================================================
--- changes/jat/oophm-branch/plugins/xpcom/FFSessionHandler.cpp (original)
+++ changes/jat/oophm-branch/plugins/xpcom/FFSessionHandler.cpp Thu Sep 25  
00:38:37 2008
@@ -96,7 +96,6 @@
      }
      // TODO(jat): what to do here?
    }
-  Debug::log(Debug::Info) << "toStringTearOff=" << JS_ValueToString(ctx,  
toStringTearOff) << Debug::flush;
  }

  FFSessionHandler::~FFSessionHandler(void) {

Modified: changes/jat/oophm-branch/plugins/xpcom/JavaObject.cpp
==============================================================================
--- changes/jat/oophm-branch/plugins/xpcom/JavaObject.cpp       (original)
+++ changes/jat/oophm-branch/plugins/xpcom/JavaObject.cpp       Thu Sep 25  
00:38:37 2008
@@ -26,15 +26,15 @@

  static JSClass JavaObjectClass = {
    "GWTJavaObject", /* class name */
-  JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1), // |  
JSCLASS_NEW_ENUMERATE, /* flags */
+  JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |  
JSCLASS_NEW_ENUMERATE, /* flags */

    JS_PropertyStub, /* add property */
    JS_PropertyStub, /* delete property */
    JavaObject::getProperty, /* get property */
    JavaObject::setProperty, /* set property */

-  JS_EnumerateStub, //  
reinterpret_cast<JSEnumerateOp>(JavaObject::enumerate), /* enumerate */
-  JS_ResolveStub, // JavaObject::resolve, /* resolve */
+  reinterpret_cast<JSEnumerateOp>(JavaObject::enumerate), /* enumerate */
+  JS_ResolveStub, /* resolve */
    JS_ConvertStub, // JavaObject::convert, /* convert */
    JavaObject::finalize, /* finalize */ //TODO

@@ -86,11 +86,13 @@
      Debug::log(Debug::Error) << "Could not set reserved slot" <<  
Debug::flush;
      return NULL;
    }
-  // define toString (TODO: some way to avoid doing this each time)
-//  if (!JS_DefineFunction(ctx, obj, "toString", JavaObject::toString, 0,  
0)) {
-//    Debug::log(Debug::Error) << "Could not define toString method on  
object"
-//        << Debug::flush;
-//  }
+  // define toString (TODO: some way to avoid doing this each time)
+#if 1
+  if (!JS_DefineFunction(ctx, obj, "toString", JavaObject::toString, 0,  
0)) {
+    Debug::log(Debug::Error) << "Could not define toString method on  
object"
+        << Debug::flush;
+  }
+#endif
    return obj;
  }

@@ -99,20 +101,21 @@
    SessionData* data = JavaObject::getSessionData(ctx, obj);
    int objectRef = JavaObject::getObjectId(ctx, obj);
    if (JSVAL_IS_STRING(id)) {
-    // only support toString
      JSString* str = JSVAL_TO_STRING(id);
-    Debug::log(Debug::Error) << "Getting string property "
-        << JS_ValueToString(ctx, id) << Debug::flush;
  #if 1
      if ((JS_GetStringLength(str) == 8) && !strncmp("toString",
            JS_GetStringBytes(str), 8)) {
        *vp = data->getToStringTearOff();
-      Debug::log(Debug::Info) << "toString tear-off returned for JavaObj("
-          << objectRef << ").toString: " << JS_ValueToString(ctx, *vp)
-          << Debug::flush;
+      return JS_TRUE;
+    }
+    if ((JS_GetStringLength(str) == 2) && !strncmp("id",
+          JS_GetStringBytes(str), 2)) {
+      *vp = INT_TO_JSVAL(objectRef);
        return JS_TRUE;
      }
  #endif
+    Debug::log(Debug::Error) << "Getting unexpected string property "
+        << JS_ValueToString(ctx, id) << Debug::flush;
      return JS_FALSE;
    }
    if (!JSVAL_IS_INT(id)) {
@@ -154,31 +157,8 @@
    return JS_TRUE;
  }

-// TODO(jat): is this actually needed, as we don't instantiate lazy  
properties?
-JSBool JavaObject::resolve(JSContext* ctx, JSObject* obj, jsval id) {
-  Debug::log(Debug::Spam) << "JavaObject::resolve obj=" << obj << "  
(objId="
-      << JavaObject::getObjectId(ctx, obj) << "), id="
-      << JS_ValueToString(ctx, id) << Debug::flush;
-#if 0
-  if (JSVAL_IS_INT(id)) {
-    // dispatch id
-    return JS_TRUE;
-  } else if (JSVAL_IS_STRING(id)) {
-    // currently only support toString
-    JSString* str = JSVAL_TO_STRING(id);
-    return (JS_GetStringLength(str) == 6) && !strncmp("toString",
-        JS_GetStringBytes(str), 6);
-  }
-  Debug::log(Debug::Error) << "JavaObject::resolve on non-int,  
non-string: "
-      << JS_ValueToString(ctx, id) << Debug::flush;
-  return JS_FALSE;
-#else
-  return JS_TRUE;
-#endif
-}
-
  JSBool JavaObject::convert(JSContext* ctx, JSObject* obj, JSType type,  
jsval* vp) {
-  Debug::log(Debug::Info) << "JavaObject::convert obj=" << obj
+  Debug::log(Debug::Spam) << "JavaObject::convert obj=" << obj
        << " type=" << type << Debug::flush;
    switch (type) {
      case JSTYPE_STRING:
@@ -189,38 +169,56 @@
      case JSTYPE_NULL:
        *vp = JSVAL_NULL;
        return JS_TRUE;
+    case JSTYPE_OBJECT:
+      *vp = OBJECT_TO_JSVAL(obj);
+      return JS_TRUE;
      default:
        break;
    }
    return JS_FALSE;
  }

+/**
+ * List of property names we want to fake on wrapped Java objects.
+ */
+static const char* propertyNames[] = {
+    "toString",
+    "id",
+};
+#define NUM_PROPERTY_NAMES (sizeof(propertyNames) /  
sizeof(propertyNames[0]))
+
  JSBool JavaObject::enumerate(JSContext* ctx, JSObject* obj, JSIterateOp op,
      jsval* statep, jsid* idp) {
+  int objectId = JavaObject::getObjectId(ctx, obj);
    switch (op) {
      case JSENUMERATE_INIT:
+      Debug::log(Debug::Spam) << "JavaObject::enumerate(oid=" << objectId
+          << ", INIT)" << Debug::flush;
        *statep = JSVAL_ZERO;
-      *idp = INT_TO_JSVAL(2);
+      if (idp) {
+        *idp = INT_TO_JSVAL(NUM_PROPERTY_NAMES);
+      }
        break;
      case JSENUMERATE_NEXT:
      {
        int idNum = JSVAL_TO_INT(*statep);
+      Debug::log(Debug::Spam) << "JavaObject::enumerate(oid=" << objectId
+          << ", NEXT " << idNum << ")" << Debug::flush;
        *statep = INT_TO_JSVAL(idNum + 1);
-      switch (idNum) {
-        case 0:
-          JS_ValueToId(ctx, STRING_TO_JSVAL("toString"), idp);
-          break;
-#if 0
-        case 1:
-          JS_ValueToId(ctx, STRING_TO_JSVAL("id"), idp);
-          break;
-#endif
-        default:
-          *statep = JSVAL_NULL;
+      if (idNum >= NUM_PROPERTY_NAMES) {
+        *statep = JSVAL_NULL;
+        *idp = JSVAL_NULL;
+      } else {
+        const char* propName = propertyNames[idNum];
+        JSString* str = JS_NewStringCopyZ(ctx, propName);
+        return JS_ValueToId(ctx, STRING_TO_JSVAL(str), idp);
        }
        break;
      }
      case JSENUMERATE_DESTROY:
+      Debug::log(Debug::Spam) << "JavaObject::enumerate(oid=" << objectId
+          << ", DESTROY)" << Debug::flush;
+      *statep = JSVAL_NULL;
        break;
    }
    return JS_TRUE;
@@ -231,14 +229,18 @@
        << " objId=" << JavaObject::getObjectId(ctx, obj) << Debug::flush;
    SessionData* data = JavaObject::getSessionData(ctx, obj);
    int objectId = JavaObject::getObjectId(ctx, obj);
-  data->freeJavaObject(objectId);
+  // TODO(jat): data can be invalid at the point this is called, causing a
+  // crash -- need to consider how to make sure it is kept around or that  
we
+  // have some way of telling it is gone so we can ignore it.
+  // data->freeJavaObject(objectId);
  }

  JSBool JavaObject::toString(JSContext* ctx, JSObject* obj, uintN argc,  
jsval* argv,
      jsval* rval) {
    SessionData* data = JavaObject::getSessionData(ctx, obj);
    int oid = getObjectId(ctx, obj);
-  Debug::log(Debug::Spam) << "JavaObject::toString(id=" << oid << data <<  
Debug::flush;
+  Debug::log(Debug::Spam) << "JavaObject::toString(id=" << oid << ")"
+      << Debug::flush;
    Value javaThis;
    javaThis.setJavaObject(oid);
    // TODO: do we care if they supply arguments?  For now we just ignore  
them.
@@ -248,8 +250,8 @@

  /**
   * Called when the JavaObject is invoked as a function.
- * We ignore the JSObject* argument, which is the 'this' context, which is  
usually the
- * window object. The JavaObject instance is in argv[-2].
+ * We ignore the JSObject* argument, which is the 'this' context, which is
+ * usually the window object. The JavaObject instance is in argv[-2].
   *
   * Returns a JS array, with the first element being a boolean indicating  
that
   * an exception occured, and the second element is either the return value  
or
@@ -264,7 +266,7 @@
      return JS_FALSE;
    }
    int dispId = JSVAL_TO_INT(argv[0]);
-  Debug::DebugStream& dbg = Debug::log(Debug::Info) << "JavaObject::call  
oid="
+  Debug::DebugStream& dbg = Debug::log(Debug::Spam) << "JavaObject::call  
oid="
        << JavaObject::getObjectId(ctx, obj) << ",dispId=" << dispId << " (";
    for (int i = 2; i < argc; ++i) {
      if (i > 2) {
@@ -285,20 +287,29 @@
      } else {
        data->makeValue(javaThis, ctx, argv[1]);
      }
+#if 0
      if (!dispId) {
-      Debug::log(Debug::Info) << "toString on " << JS_ValueToString(ctx,  
argv[1]) << " called" << Debug::flush;
+      Debug::log(Debug::Spam) << "toString called" << Debug::flush;
      }
+#endif
    } else {
      int oid = getObjectId(ctx, obj);
      javaThis.setJavaObject(oid);
+#if 0
      if (!dispId) {
-      Debug::log(Debug::Info) << "toString on JavaObj(" << oid << ")  
called"
+      Debug::log(Debug::Spam) << "toString on JavaObj(" << oid << ")  
called"
            << Debug::flush;
      }
+#endif
    }
    return invokeJava(ctx, data, javaThis, dispId, argc - 2, &argv[2], rval);
  }

+/**
+ * Calls a method on a Java object and returns a two-element JS array, with
+ * the first element being a boolean flag indicating an exception was  
thrown,
+ * and the second element is the actual return value or exception.
+ */
  JSBool JavaObject::invokeJava(JSContext* ctx, SessionData* data,
      const Value& javaThis, int dispId, int numArgs, const jsval* jsargs,
      jsval* rval) {

--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---

Reply via email to