Permalink
Browse files

Fix COUCHDB-1078 - Port couchjs to newest libmozjs

As usually, please test and report any build system problems as I
cannot test every configuration.

Thanks to Chris Coulson for the original patch.

git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@1137464 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information...
1 parent 0cd6405 commit 7b0f330627c9f3ef1ccb9e3ffe1e909e3a27f1bf @tilgovi tilgovi committed Jun 19, 2011
Showing with 327 additions and 74 deletions.
  1. +1 −0 THANKS
  2. +65 −17 configure.ac
  3. +38 −19 src/couchdb/priv/couch_js/http.c
  4. +91 −0 src/couchdb/priv/couch_js/jscompat.h
  5. +125 −36 src/couchdb/priv/couch_js/main.c
  6. +7 −2 src/couchdb/priv/couch_js/utf8.c
View
1 THANKS
@@ -83,6 +83,7 @@ suggesting improvements or submitting changes. Some of these people are:
* Nathan Vander Wilt <natevw@yahoo.com>
* Caolan McMahon <caolan.mcmahon@googlemail.com>
* Andrey Somov <trophybase@gmail.com>
+ * Chris Coulson <chrisccoulson.googlemail.com>
For a list of authors see the `AUTHORS` file.
View
@@ -121,15 +121,19 @@ AC_ARG_WITH([erlang], [AC_HELP_STRING([--with-erlang=PATH],
])
AC_SUBST(ERLANG_FLAGS)
-PKG_CHECK_MODULES([JS], [mozilla-js >= 1.7], [
- JS_LIB_DIR="$(${PKG_CONFIG} --variable=sdkdir mozilla-js)/lib"
+PKG_CHECK_MODULES([JS], [mozjs185], [
+ JS_LIB_DIR="$(${PKG_CONFIG} --variable=libdir mozjs185)"
+], [
+ PKG_CHECK_MODULES([JS], [mozilla-js >= 1.7], [
+ JS_LIB_DIR="$(${PKG_CONFIG} --variable=sdkdir mozilla-js)/lib"
], [
- JS_LIB_DIR="${libdir}"
- JS_CFLAGS="-I/usr/include"
- JS_CFLAGS="$JS_CFLAGS -I/usr/include/js"
- JS_CFLAGS="$JS_CFLAGS -I/usr/include/mozjs"
- JS_CFLAGS="$JS_CFLAGS -I/usr/local/include/js"
- JS_CFLAGS="$JS_CFLAGS -I/opt/local/include/js"
+ JS_LIB_DIR="${libdir}"
+ JS_CFLAGS="-I/usr/include"
+ JS_CFLAGS="$JS_CFLAGS -I/usr/include/js"
+ JS_CFLAGS="$JS_CFLAGS -I/usr/include/mozjs"
+ JS_CFLAGS="$JS_CFLAGS -I/usr/local/include/js"
+ JS_CFLAGS="$JS_CFLAGS -I/opt/local/include/js"
+ ])
])
AC_ARG_WITH([js-include], [AC_HELP_STRING([--with-js-include=PATH],
@@ -175,16 +179,40 @@ AM_CONDITIONAL([WINDOWS], [test x$IS_WINDOWS = xTRUE])
OLD_LIBS="$LIBS"
LIBS="$JS_LIBS $LIBS"
-AC_CHECK_LIB([mozjs], [JS_NewContext], [JS_LIB_BASE=mozjs], [
- AC_CHECK_LIB([js], [JS_NewContext], [JS_LIB_BASE=js], [
- AC_CHECK_LIB([js3250], [JS_NewContext], [JS_LIB_BASE=js3250], [
- AC_CHECK_LIB([js32], [JS_NewContext], [JS_LIB_BASE=js32], [
- AC_MSG_ERROR([Could not find the js library.
-
-Is the Mozilla SpiderMonkey library installed?])])])])])
+AC_CHECK_LIB([mozjs185], [JS_NewContext], [JS_LIB_BASE=mozjs185], [
+ AC_CHECK_LIB([mozjs], [JS_NewContext], [JS_LIB_BASE=mozjs], [
+ AC_CHECK_LIB([js], [JS_NewContext], [JS_LIB_BASE=js], [
+ AC_CHECK_LIB([js3250], [JS_NewContext], [JS_LIB_BASE=js3250], [
+ AC_CHECK_LIB([js32], [JS_NewContext], [JS_LIB_BASE=js32], [
+ AC_MSG_ERROR([Could not find the js library.
+
+Is the Mozilla SpiderMonkey library installed?])])])])])])
+
+AC_CHECK_LIB([$JS_LIB_BASE], [JS_FreezeObject],
+ AC_DEFINE([HAVE_JS_FREEZE_OBJECT], [1],
+ [Define whether we have JS_FreezeObject]))
+
+AC_CHECK_LIB([$JS_LIB_BASE], [JS_NewGlobalObject],
+ AC_DEFINE([HAVE_JS_NEW_GLOBAL_OBJECT], [1],
+ [Define whether we have JS_NewGlobalObject]))
+
+AC_CHECK_LIB([$JS_LIB_BASE], [JS_GetStringCharsAndLength],
+ AC_DEFINE([HAVE_JS_GET_STRING_CHARS_AND_LENGTH], [1],
+ [Define whether we have JS_GetStringCharsAndLength]))
+
+AC_CHECK_LIB([$JS_LIB_BASE], [JS_NewCompartmentAndGlobalObject],
+ AC_DEFINE([HAVE_COMPARTMENTS], [1],
+ [Define whether we have JS_NewCompartmentAndGlobalObject]))
+
+AC_CHECK_LIB([$JS_LIB_BASE], [JS_StrictPropertyStub],
+ AC_DEFINE([HAVE_JS_STRICT_PROPERTY_STUB], [1],
+ [Define whether we have JS_StrictPropertyStub]))
+
+AC_CHECK_LIB([$JS_LIB_BASE], [JS_DestroyScript],
+ AC_DEFINE([HAVE_SCRIPT_TYPE], [1],
+ [Define whether scripts have a special JSScript type]))
LIBS="$OLD_LIBS"
-
if test x${IS_WINDOWS} = xTRUE; then
if test -f "$JS_LIB_DIR/$JS_LIB_BASE.dll"; then
# seamonkey 1.7- build layout on Windows
@@ -247,14 +275,34 @@ CPPFLAGS="$OLD_CPPFLAGS"
AC_LANG_PUSH(C)
OLDCFLAGS="$CFLAGS"
-CFLAGS="-Werror-implicit-function-declaration $CFLAGS"
+CFLAGS="-Werror-implicit-function-declaration $JS_CFLAGS $OLDCFLAGS"
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[#include <jsapi.h>]],
[[JS_SetOperationCallback(0, 0);]]
)],
AC_DEFINE([USE_JS_SETOPCB], [], [Use new JS_SetOperationCallback])
)
+CFLAGS="$JS_CFLAGS $OLDCFLAGS"
+AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#include <jsapi.h>]],
+ [[static JSFunctionSpec fs;
+ fs.extra = 0;]]
+ )],
+ AC_DEFINE([JS_FS_HAS_EXTRA], [1], [JSFunctionSpec has an extra member])
+)
+CFLAGS="$JS_CFLAGS $OLDCFLAGS -Werror"
+AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#include <jsapi.h>
+ static JSBool op(JSContext* cx, JSObject* obj, jsid id, jsval* vp) {}]],
+ [[static JSPropertySpec spec;
+ spec.getter = op;]]
+ )],
+ AC_DEFINE([JS_PROPERTY_OP_HAS_ID_AS_JSID], [1],
+ [The type of "id" in the prototype for JSPropertyOp is a jsid])
+)
CFLAGS="$OLD_CFLAGS"
AC_LANG_POP(C)
@@ -10,12 +10,11 @@
// License for the specific language governing permissions and limitations under
// the License.
-#include "config.h"
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jsapi.h>
+#include "config.h"
#ifndef HAVE_CURL
@@ -34,6 +33,7 @@ install_http(JSContext* cx, JSObject* glbl)
#include <curl/curl.h>
#include "utf8.h"
+#include "jscompat.h"
#ifdef XP_WIN
// Map some of the string function names to things which exist on Windows
@@ -66,12 +66,14 @@ go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t blen);
static JSString*
str_from_binary(JSContext* cx, char* data, size_t length);
-static JSBool
-constructor(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
+COUCHJS_CONSTRUCTOR_DECLARE(constructor)
{
+ COUCHJS_CONSTRUCTOR_INIT_VARS
HTTPData* http = NULL;
JSBool ret = JS_FALSE;
+ COUCHJS_CONSTRUCTOR_CONSTRUCT
+
http = (HTTPData*) malloc(sizeof(HTTPData));
if(!http)
{
@@ -89,7 +91,8 @@ constructor(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
JS_ReportError(cx, "Failed to set private CouchHTTP data.");
goto error;
}
-
+
+ COUCHJS_CONSTRUCTOR_FINISH
ret = JS_TRUE;
goto success;
@@ -106,7 +109,10 @@ destructor(JSContext* cx, JSObject* obj)
HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
if(!http)
{
- fprintf(stderr, "Unable to destroy invalid CouchHTTP instance.\n");
+ // mozjs185 seems to create a ghost object that gets finalized
+ // No messing about with flags seems to prevent this or ensure it's
+ // constructed properly.
+ fprintf(stderr, "No valid CouchHTTP instance to destroy [harmless].\n");
}
else
{
@@ -117,8 +123,9 @@ destructor(JSContext* cx, JSObject* obj)
}
static JSBool
-open(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
-{
+open(JSContext* cx, uintN argc, jsval* vp)
+{
+ COUCHJS_NATIVE_INIT_VARS(argv, obj)
HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
char* method = NULL;
char* url = NULL;
@@ -191,6 +198,7 @@ open(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
// Disable Expect: 100-continue
http->req_headers = curl_slist_append(http->req_headers, "Expect:");
+ JS_SET_RVAL(cx, vp, JSVAL_VOID);
ret = JS_TRUE;
done:
@@ -199,8 +207,9 @@ open(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
}
static JSBool
-setheader(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
-{
+setheader(JSContext* cx, uintN argc, jsval* vp)
+{
+ COUCHJS_NATIVE_INIT_VARS(argv, obj)
HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
char* keystr = NULL;
char* valstr = NULL;
@@ -251,6 +260,7 @@ setheader(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
snprintf(hdrbuf, hdrlen, "%s: %s", keystr, valstr);
http->req_headers = curl_slist_append(http->req_headers, hdrbuf);
+ JS_SET_RVAL(cx, vp, JSVAL_VOID);
ret = JS_TRUE;
done:
@@ -262,8 +272,9 @@ setheader(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
}
static JSBool
-sendreq(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
+sendreq(JSContext* cx, uintN argc, jsval* vp)
{
+ COUCHJS_NATIVE_INIT_VARS(argv, obj)
HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
char* body = NULL;
size_t bodylen = 0;
@@ -286,14 +297,15 @@ sendreq(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
}
ret = go(cx, obj, http, body, bodylen);
+ if (ret == JS_TRUE)
+ JS_SET_RVAL(cx, vp, JSVAL_VOID);
done:
if(body) free(body);
return ret;
}
-static JSBool
-status(JSContext* cx, JSObject* obj, jsval idval, jsval* vp)
+COUCHJS_GETTER_DECLARE(status)
{
HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
@@ -302,7 +314,13 @@ status(JSContext* cx, JSObject* obj, jsval idval, jsval* vp)
JS_ReportError(cx, "Invalid CouchHTTP instance.");
return JS_FALSE;
}
-
+
+#ifndef INT_FITS_IN_JSVAL
+ // jsval's are 64-bits wide in mozjs >= 2.0, so a jsint can use a full
+ // 32-bits now no bits are reserved for tagging
+ *vp = INT_TO_JSVAL(http->last_status);
+ return JS_TRUE;
+#else
if(INT_FITS_IN_JSVAL(http->last_status))
{
*vp = INT_TO_JSVAL(http->last_status);
@@ -313,6 +331,7 @@ status(JSContext* cx, JSObject* obj, jsval idval, jsval* vp)
JS_ReportError(cx, "INTERNAL: Invalid last_status");
return JS_FALSE;
}
+#endif
}
JSClass CouchHTTPClass = {
@@ -323,7 +342,7 @@ JSClass CouchHTTPClass = {
JS_PropertyStub,
JS_PropertyStub,
JS_PropertyStub,
- JS_PropertyStub,
+ JS_SETPROPERTY_PROPERTY_STUB,
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
@@ -337,10 +356,10 @@ JSPropertySpec CouchHTTPProperties[] = {
};
JSFunctionSpec CouchHTTPFunctions[] = {
- {"_open", open, 3, 0, 0},
- {"_setRequestHeader", setheader, 2, 0, 0},
- {"_send", sendreq, 1, 0, 0},
- {0, 0, 0, 0, 0}
+ JS_FS("_open", COUCHJS_NATIVE_FUNC(open), 3, JSFUN_FAST_NATIVE),
+ JS_FS("_setRequestHeader", COUCHJS_NATIVE_FUNC(setheader), 2, JSFUN_FAST_NATIVE),
+ JS_FS("_send", COUCHJS_NATIVE_FUNC(sendreq), 1, JSFUN_FAST_NATIVE),
+ JS_FS_END
};
JSObject*
@@ -0,0 +1,91 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef COUCH_JS_JS_COMPAT_H
+#define COUCH_JS_JS_COMPAT_H
+
+#ifdef JS_FS_HAS_EXTRA
+# undef JS_FS
+# undef JS_FS_END
+# define JS_FS(name,call,nargs,flags) {name, call, nargs, flags, 0}
+# define JS_FS_END JS_FS(0, 0, 0, 0)
+#endif
+
+#ifdef JSFUN_CONSTRUCTOR
+# define JSFUN_FAST_NATIVE 0
+# define COUCHJS_CONSTRUCTOR_DECLARE(name) \
+ static JSBool \
+ name(JSContext* cx, uintN argc, jsval* vp)
+# define COUCHJS_CONSTRUCTOR_INIT_VARS \
+ JSObject *obj = NULL; \
+ jsval *argv = JS_ARGV(cx, vp);
+# define COUCHJS_CONSTRUCTOR_CONSTRUCT \
+ obj = JS_NewObjectForConstructor(cx, vp); \
+ if(!obj) { \
+ JS_ReportError(cx, "Failed to create 'this' object"); \
+ return JS_FALSE; \
+ }
+# define COUCHJS_CONSTRUCTOR_FINISH \
+ JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
+# define COUCHJS_NATIVE_FUNC(func) func
+#else
+# define COUCHJS_CONSTRUCTOR_DECLARE(name) \
+ static JSBool \
+ name(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
+# define COUCHJS_CONSTRUCTOR_INIT_VARS
+# define COUCHJS_CONSTRUCTOR_CONSTRUCT
+# define COUCHJS_CONSTRUCTOR_FINISH
+# define COUCHJS_NATIVE_FUNC(func) (JSNative) func
+#endif
+
+#ifdef HAVE_JS_STRICT_PROPERTY_STUB
+# define JS_SETPROPERTY_PROPERTY_STUB JS_StrictPropertyStub
+#else
+# define JS_SETPROPERTY_PROPERTY_STUB JS_PropertyStub
+#endif
+
+#ifdef HAVE_SCRIPT_TYPE
+# define COUCHJS_SCRIPT JSScript
+# define COUCHJS_DESTROY_SCRIPT(cx, script) \
+ JS_DestroyScript(cx, script)
+#else
+# define COUCHJS_SCRIPT JSObject
+# define COUCHJS_DESTROY_SCRIPT(cx, script)
+#endif
+
+#ifdef HAVE_JS_FREEZE_OBJECT
+# define COUCHJS_SEAL_OBJECT(res, cx, target, deep) \
+ res = deep ? JS_DeepFreezeObject(cx, target) : JS_FreezeObject(cx, target);
+#else
+# define COUCHJS_SEAL_OBJECT(res, cx, target, deep) \
+ res = JS_SealObject(cx, target, deep);
+#endif
+
+#define COUCHJS_NATIVE_INIT_VARS(argv, obj) \
+ jsval* argv = JS_ARGV(cx, vp); \
+ JSObject* obj = JS_THIS_OBJECT(cx, vp); \
+ if (!obj) { \
+ JS_ReportError(cx, "No 'this' object"); \
+ return JS_FALSE; \
+ }
+
+#ifdef JS_PROPERTY_OP_HAS_ID_AS_JSID
+# define COUCHJS_GETTER_DECLARE(name) \
+ static JSBool \
+ status(JSContext* cx, JSObject* obj, jsid id, jsval* vp)
+#else
+# define COUCHJS_GETTER_DECLARE(name) \
+ static JSBool \
+ status(JSContext* cx, JSObject* obj, jsval idval, jsval* vp)
+#endif
+
+#endif
Oops, something went wrong.

0 comments on commit 7b0f330

Please sign in to comment.