build: Pull pacrunner forward to mozjs38

Mozjs185 is getting really old and unsupported. Newer versions
of the mozjs JSAPI are C++ based. So we convert the plugin to
C++ and then apply necessarily API changes so that it can be built
with the more recent mozjs38. For example we now need to "root"
values being passed into the API in order to satisfy the JSAPI
garbage collection rules. Further, a number of the APIs have been
tweaked and moved into the JS namespace, so we namespace them
appropriately and adjust their parameters.
diff --git a/Makefile.am b/Makefile.am
index ee84b75..65cc8c9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -31,9 +31,10 @@
 if MOZJS
 js_sources = src/js_funcs.c
 builtin_modules += mozjs
-builtin_sources += plugins/mozjs.c
-builtin_cflags += @MOZJS_CFLAGS@
-builtin_libadd += @MOZJS_LIBS@
+builtin_libadd += plugins/libmozjsplugin.a @MOZJS_LIBS@ -lstdc++
+noinst_LIBRARIES += plugins/libmozjsplugin.a
+plugins_libmozjsplugin_a_SOURCES = plugins/mozjs.cc
+plugins_libmozjsplugin_a_CXXFLAGS = $(AM_CFLAGS) @MOZJS_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@
 endif
 
 if V8
@@ -137,16 +138,16 @@
 endif
 
 if MOZJS
-unit_test_pacrunner_SOURCES += plugins/mozjs.c
-
+unit_test_pacrunner_SOURCES += plugins/mozjs.cc
+unit_test_pacrunner_CXXFLAGS = $(AM_CFLAGS)  @MOZJS_CFLAGS@
 unit_test_pacrunner_LDADD += @MOZJS_LIBS@ @PTHREAD_LIBS@
 
 noinst_PROGRAMS += unit/test-mozjs
 
 unit_test_mozjs_SOURCES = unit/test-mozjs.c src/pacrunner.h \
 			src/proxy.c src/manual.c src/download.c \
-				src/js.c plugins/mozjs.c $(js_sources)
-
+				src/js.c plugins/mozjs.cc $(js_sources)
+unit_test_mozjs_CXXFLAGS = $(AM_CFLAGS)  @MOZJS_CFLAGS@
 unit_test_mozjs_LDADD = @MOZJS_LIBS@ @GLIB_LIBS@ @PTHREAD_LIBS@
 endif
 
diff --git a/configure.ac b/configure.ac
index 888c873..bf76fbb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -76,8 +76,8 @@
 AC_ARG_ENABLE(mozjs, AC_HELP_STRING([--enable-mozjs],
 		[enable Mozilla Javascript plugin support]))
 if (test "${enable_mozjs}" = "yes"); then
-	PKG_CHECK_MODULES(MOZJS,  mozjs185, dummy=yes,
-			AC_MSG_ERROR(Mozilla Javascript >= 1.8 is required))
+	PKG_CHECK_MODULES(MOZJS,  mozjs-38, dummy=yes,
+			AC_MSG_ERROR(Mozilla Javascript version 38 is required))
 	AC_SUBST(MOZJS_CFLAGS)
 	AC_SUBST(MOZJS_LIBS)
 fi
diff --git a/plugins/mozjs.c b/plugins/mozjs.c
deleted file mode 100644
index a923203..0000000
--- a/plugins/mozjs.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- *
- *  PACrunner - Proxy configuration daemon
- *
- *  Copyright (C) 2010-2011  Intel Corporation. All rights reserved.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <pthread.h>
-
-#include <netdb.h>
-
-#pragma GCC diagnostic ignored "-Wredundant-decls"
-#include <jsapi.h>
-#pragma GCC diagnostic error "-Wredundant-decls"
-
-#include "pacrunner.h"
-#include "js.h"
-
-static pthread_mutex_t mozjs_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-struct pacrunner_mozjs {
-	struct pacrunner_proxy *proxy;
-	JSContext *jsctx;
-	JSObject *jsobj;
-};
-
-static JSBool myipaddress(JSContext *jsctx, uintN argc, jsval *vp)
-{
-	struct pacrunner_mozjs *ctx = JS_GetContextPrivate(jsctx);
-	char address[NI_MAXHOST];
-
-	DBG("");
-
-	JS_SET_RVAL(jsctx, vp, JSVAL_NULL);
-
-	if (!ctx)
-		return JS_TRUE;
-
-	if (__pacrunner_js_getipaddr(ctx->proxy, address, sizeof(address)) < 0)
-		return JS_TRUE;
-
-	DBG("address %s", address);
-
-	JS_SET_RVAL(jsctx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(jsctx,
-							       address)));
-
-	return JS_TRUE;
-}
-
-static JSBool dnsresolve(JSContext *jsctx, uintN argc, jsval *vp)
-{
-	struct pacrunner_mozjs *ctx = JS_GetContextPrivate(jsctx);
-	char address[NI_MAXHOST];
-	jsval *argv = JS_ARGV(jsctx, vp);
-	char *host = JS_EncodeString(jsctx, JS_ValueToString(jsctx, argv[0]));
-
-	DBG("host %s", host);
-
-	JS_SET_RVAL(jsctx, vp, JSVAL_NULL);
-
-	if (!ctx)
-		goto out;
-
-	if (__pacrunner_js_resolve(ctx->proxy, host, address, sizeof(address)) < 0)
-		goto out;
-
-	DBG("address %s", address);
-
-	JS_SET_RVAL(jsctx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(jsctx, address)));
-
- out:
-	JS_free(jsctx, host);
-	return JS_TRUE;
-
-}
-
-static JSClass jscls = {
-	"global", JSCLASS_GLOBAL_FLAGS,
-	JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
-	JS_StrictPropertyStub,
-	JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
-	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
-};
-
-static JSRuntime *jsrun;
-
-static int create_object(struct pacrunner_proxy *proxy)
-{
-	struct pacrunner_mozjs *ctx;
-	const char *script;
-	jsval rval;
-
-	script = pacrunner_proxy_get_script(proxy);
-	if (!script)
-		return 0;
-
-	ctx = g_malloc0(sizeof(struct pacrunner_mozjs));
-
-	ctx->proxy = proxy;
-	ctx->jsctx = JS_NewContext(jsrun, 8 * 1024);
-	if (!ctx->jsctx) {
-		g_free(ctx);
-		return -ENOMEM;
-	}
-	JS_SetContextPrivate(ctx->jsctx, ctx);
-	__pacrunner_proxy_set_jsctx(proxy, ctx);
-
-#if JS_VERSION >= 185
-	ctx->jsobj = JS_NewCompartmentAndGlobalObject(ctx->jsctx, &jscls,
-						      NULL);
-#else
-	ctx->jsobj = JS_NewObject(ctx->jsctx, &jscls, NULL, NULL);
-#endif
-
-	if (!JS_InitStandardClasses(ctx->jsctx, ctx->jsobj))
-		pacrunner_error("Failed to init JS standard classes");
-
-	JS_DefineFunction(ctx->jsctx, ctx->jsobj, "myIpAddress",
-			  myipaddress, 0, 0);
-	JS_DefineFunction(ctx->jsctx, ctx->jsobj,
-			  "dnsResolve", dnsresolve, 1, 0);
-
-	JS_EvaluateScript(ctx->jsctx, ctx->jsobj, __pacrunner_js_routines,
-			  strlen(__pacrunner_js_routines), NULL, 0, &rval);
-
-	JS_EvaluateScript(ctx->jsctx, ctx->jsobj, script, strlen(script),
-			  "wpad.dat", 0, &rval);
-
-	return 0;
-}
-
-static int mozjs_clear_proxy(struct pacrunner_proxy *proxy)
-{
-	struct pacrunner_mozjs *ctx = __pacrunner_proxy_get_jsctx(proxy);
-
-	DBG("proxy %p ctx %p", proxy, ctx);
-
-	if (!ctx)
-		return -EINVAL;
-
-	JS_DestroyContext(ctx->jsctx);
-	__pacrunner_proxy_set_jsctx(proxy, NULL);
-
-	return 0;
-}
-
-static int mozjs_set_proxy(struct pacrunner_proxy *proxy)
-{
-	DBG("proxy %p", proxy);
-
-	if (!proxy)
-		return 0;
-
-	mozjs_clear_proxy(proxy);
-
-	return create_object(proxy);
-}
-
-static char * mozjs_execute(struct pacrunner_proxy *proxy, const char *url,
-			    const char *host)
-{
-	struct pacrunner_mozjs *ctx = __pacrunner_proxy_get_jsctx(proxy);
-	JSBool result;
-	jsval rval, args[2];
-	char *answer, *g_answer;
-
-	DBG("proxy %p ctx %p url %s host %s", proxy, ctx, url, host);
-
-	if (!ctx)
-		return NULL;
-
-	pthread_mutex_lock(&mozjs_mutex);
-
-	JS_BeginRequest(ctx->jsctx);
-
-	args[0] = STRING_TO_JSVAL(JS_NewStringCopyZ(ctx->jsctx, url));
-	args[1] = STRING_TO_JSVAL(JS_NewStringCopyZ(ctx->jsctx, host));
-
-	result = JS_CallFunctionName(ctx->jsctx, ctx->jsobj,
-				     "FindProxyForURL", 2, args, &rval);
-
-	JS_EndRequest(ctx->jsctx);
-
-	JS_MaybeGC(ctx->jsctx);
-
-	pthread_mutex_unlock(&mozjs_mutex);
-
-	if (result) {
-		answer = JS_EncodeString(ctx->jsctx,
-					 JS_ValueToString(ctx->jsctx, rval));
-		g_answer = g_strdup(answer);
-		JS_free(ctx->jsctx, answer);
-		return g_answer;
-	}
-
-	return NULL;
-}
-
-static struct pacrunner_js_driver mozjs_driver = {
-	.name		= "mozjs",
-	.priority	= PACRUNNER_JS_PRIORITY_DEFAULT,
-	.set_proxy	= mozjs_set_proxy,
-	.clear_proxy	= mozjs_clear_proxy,
-	.execute	= mozjs_execute,
-};
-
-static int mozjs_init(void)
-{
-	DBG("");
-
-	jsrun = JS_NewRuntime(8 * 1024 * 1024);
-
-	return pacrunner_js_driver_register(&mozjs_driver);
-}
-
-static void mozjs_exit(void)
-{
-	DBG("");
-
-	pacrunner_js_driver_unregister(&mozjs_driver);
-
-	JS_DestroyRuntime(jsrun);
-}
-
-PACRUNNER_PLUGIN_DEFINE(mozjs, mozjs_init, mozjs_exit)
diff --git a/plugins/mozjs.cc b/plugins/mozjs.cc
new file mode 100644
index 0000000..e10b297
--- /dev/null
+++ b/plugins/mozjs.cc
@@ -0,0 +1,253 @@
+/*
+ *
+ *  PACrunner - Proxy configuration daemon
+ *
+ *  Copyright (C) 2010-2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+
+#include <netdb.h>
+
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#pragma GCC diagnostic ignored "-Winvalid-offsetof"
+#include <jsapi.h>
+#pragma GCC diagnostic error "-Wredundant-decls"
+#pragma GCC diagnostic error "-Winvalid-offsetof"
+
+extern "C" {
+#include "pacrunner.h"
+#include "js.h"
+}
+
+static pthread_mutex_t mozjs_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+struct pacrunner_mozjs {
+	struct pacrunner_proxy *proxy;
+	JSContext *jsctx;
+	JSObject *jsobj;
+	JSAutoCompartment *jsac;
+};
+
+static bool myipaddress(JSContext *jsctx, unsigned argc, jsval *vp)
+{
+	struct pacrunner_mozjs *ctx = (pacrunner_mozjs *)JS_GetContextPrivate(jsctx);
+	char address[NI_MAXHOST];
+
+	DBG("");
+
+	JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+
+	args.rval().setNull();
+
+	if (!ctx)
+		return true;
+
+	if (__pacrunner_js_getipaddr(ctx->proxy, address, sizeof(address)) < 0)
+		return true;
+
+	DBG("address %s", address);
+
+	args.rval().setString(JS_NewStringCopyZ(jsctx,address));
+
+	return true;
+}
+
+static bool dnsresolve(JSContext *jsctx, unsigned argc, jsval *vp)
+{
+	struct pacrunner_mozjs *ctx = (pacrunner_mozjs *)JS_GetContextPrivate(jsctx);
+	char address[NI_MAXHOST];
+	JS::CallArgs args = JS::CallArgsFromVp(argc,vp);
+	char * host = JS_EncodeString(jsctx, args[0].toString());
+
+	DBG("host %s", host);
+
+	if (!ctx)
+		goto out;
+
+	if (__pacrunner_js_resolve(ctx->proxy, host, address, sizeof(address)) < 0)
+		goto out;
+
+	DBG("address %s", address);
+
+	args.rval().setString(JS_NewStringCopyZ(jsctx,address));
+
+ out:
+	JS_free(jsctx, host);
+	return true;
+
+}
+
+static JSClass jscls = {
+	"global", JSCLASS_GLOBAL_FLAGS,
+};
+
+static JSRuntime *jsrun;
+
+static int create_object(struct pacrunner_proxy *proxy)
+{
+	struct pacrunner_mozjs *ctx;
+	const char *script;
+
+	script = pacrunner_proxy_get_script(proxy);
+	if (!script)
+		return 0;
+
+	ctx = (pacrunner_mozjs *)g_malloc0(sizeof(struct pacrunner_mozjs));
+
+	ctx->proxy = proxy;
+	ctx->jsctx = JS_NewContext(jsrun, 8 * 1024);
+	if (!ctx->jsctx) {
+		g_free(ctx);
+		return -ENOMEM;
+	}
+	JS_SetContextPrivate(ctx->jsctx, ctx);
+	__pacrunner_proxy_set_jsctx(proxy, ctx);
+
+	JS::CompartmentOptions compart_opts;
+	compart_opts.setVersion(JSVERSION_LATEST);
+	ctx->jsobj = JS_NewGlobalObject(ctx->jsctx, &jscls, nullptr,
+					JS::DontFireOnNewGlobalHook, compart_opts);
+	JS::RootedObject jsobj(ctx->jsctx,ctx->jsobj);
+
+	ctx->jsac = new JSAutoCompartment(ctx->jsctx, jsobj);
+
+	if (!JS_InitStandardClasses(ctx->jsctx, jsobj))
+		pacrunner_error("Failed to init JS standard classes");
+
+	JS_DefineFunction(ctx->jsctx, jsobj, "myIpAddress", myipaddress, 0, 0);
+	JS_DefineFunction(ctx->jsctx, jsobj, "dnsResolve", dnsresolve, 1, 0);
+
+	JS::RootedValue rval(ctx->jsctx);
+	JS::CompileOptions opts(ctx->jsctx);
+	opts.setIntroductionType("pacrunner")
+	    .setUTF8(true)
+	    .setCompileAndGo(true);
+
+	JS::Evaluate(ctx->jsctx, JS::HandleObject(jsobj), opts,
+		     __pacrunner_js_routines, strlen(__pacrunner_js_routines)
+		     , &rval);
+
+	JS::Evaluate(ctx->jsctx, jsobj, opts, script, strlen(script), &rval);
+
+	return 0;
+}
+
+static int mozjs_clear_proxy(struct pacrunner_proxy *proxy)
+{
+	struct pacrunner_mozjs *ctx = (pacrunner_mozjs *)__pacrunner_proxy_get_jsctx(proxy);
+
+	DBG("proxy %p ctx %p", proxy, ctx);
+
+	if (!ctx)
+		return -EINVAL;
+
+	delete ctx->jsac;
+	JS_DestroyContext(ctx->jsctx);
+	__pacrunner_proxy_set_jsctx(proxy, NULL);
+	g_free(ctx);
+
+	return 0;
+}
+
+static int mozjs_set_proxy(struct pacrunner_proxy *proxy)
+{
+	DBG("proxy %p", proxy);
+	if (!proxy)
+		return 0;
+
+	mozjs_clear_proxy(proxy);
+
+	return create_object(proxy);
+}
+
+static char * mozjs_execute(struct pacrunner_proxy *proxy, const char *url,
+			    const char *host)
+{
+	struct pacrunner_mozjs *ctx = (pacrunner_mozjs *)__pacrunner_proxy_get_jsctx(proxy);
+	bool result;
+	char *answer, *g_answer;
+	DBG("proxy %p ctx %p url %s host %s", proxy, ctx, url, host);
+
+	if (!ctx)
+		return NULL;
+
+	pthread_mutex_lock(&mozjs_mutex);
+
+	JS_BeginRequest(ctx->jsctx);
+	JS::RootedValue rval(ctx->jsctx);
+	JS::AutoValueArray<2> args(ctx->jsctx);
+
+	args[0].setString(JS_NewStringCopyZ(ctx->jsctx, url));
+	args[1].setString(JS_NewStringCopyZ(ctx->jsctx, host));
+
+
+	JS::RootedObject jsobj(ctx->jsctx,ctx->jsobj);
+
+	result = JS_CallFunctionName(ctx->jsctx, jsobj, "FindProxyForURL", args , &rval);
+
+	JS_EndRequest(ctx->jsctx);
+
+	JS_MaybeGC(ctx->jsctx);
+
+	pthread_mutex_unlock(&mozjs_mutex);
+
+	if (result) {
+		answer = JS_EncodeString(ctx->jsctx, rval.toString());
+		g_answer = g_strdup(answer);
+		JS_free(ctx->jsctx, answer);
+		return g_answer;
+	}
+
+	return NULL;
+}
+
+static struct pacrunner_js_driver mozjs_driver = {
+	.name		= "mozjs",
+	.priority	= PACRUNNER_JS_PRIORITY_DEFAULT,
+	.set_proxy	= mozjs_set_proxy,
+	.clear_proxy	= mozjs_clear_proxy,
+	.execute	= mozjs_execute,
+};
+
+static int mozjs_init(void)
+{
+	DBG("");
+	JS_Init();
+	jsrun = JS_NewRuntime(JS::DefaultHeapMaxBytes, 8 * 1024 * 1024 );
+
+	return pacrunner_js_driver_register(&mozjs_driver);
+}
+
+static void mozjs_exit(void)
+{
+	DBG("");
+
+	pacrunner_js_driver_unregister(&mozjs_driver);
+
+	JS_DestroyRuntime(jsrun);
+	JS_ShutDown();
+}
+
+PACRUNNER_PLUGIN_DEFINE(mozjs, mozjs_init, mozjs_exit)