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
-~----------~----~----~----~------~----~------~--~---