diff -Naur elinks-0.12pre5/configure.in elinks-0.12pre5.new/configure.in
--- elinks-0.12pre5/configure.in	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/configure.in	2012-05-05 19:24:29.000000000 +0200
@@ -283,6 +283,7 @@
 AC_CHECK_FUNCS(getifaddrs getpwnam inet_pton inet_ntop)
 AC_CHECK_FUNCS(fflush fsync fseeko ftello sigaction)
 AC_CHECK_FUNCS(gettimeofday clock_gettime)
+AC_CHECK_FUNCS(setitimer, HAVE_SETITIMER=yes)

 AC_CHECK_FUNCS([cygwin_conv_to_full_win32_path])

@@ -640,7 +641,15 @@
 					CPPFLAGS="$CPPFLAGS_X $SPIDERMONKEY_CFLAGS"

 					AC_LINK_IFELSE([AC_LANG_PROGRAM([[#define XP_UNIX
-						     #include <jsapi.h>]], [[JS_GetReservedSlot(NULL, NULL, 0, NULL)]])],[cf_result=yes],[cf_result=no])
+							#define XP_UNIX
+							#include <jsapi.h>]], [[
+							#ifndef JS_VERSION
+							#error JS_VERSION
+							#endif
+							#if JS_VERSION < 185
+							#error too old
+							#endif]])],
+                            [cf_result=yes],[cf_result=no])
 				fi
 			done
 		done
@@ -651,6 +660,9 @@
 CONFIG_SPIDERMONKEY="$cf_result"
 if test "$cf_result" = "yes"; then
 	AC_CHECK_FUNCS([[JS_ReportAllocationOverflow]])
+	AC_CHECK_FUNCS(JS_SetBranchCallback)
+	AC_CHECK_FUNCS(JS_TriggerOperationCallback, HAVE_JS_TRIGGEROPERATIONCALLBACK=yes)
+
 fi
 EL_RESTORE_FLAGS

@@ -665,6 +677,16 @@
 AC_SUBST(CONFIG_ECMASCRIPT_SEE)
 AC_SUBST(CONFIG_ECMASCRIPT_SMJS)

+if test "x$CONFIG_ECMASCRIPT_SMJS" = xyes &&
+   test "x$HAVE_JS_TRIGGEROPERATIONCALLBACK" = xyes &&
+   test "x$HAVE_SETITIMER" = xyes; then
+	EL_CONFIG(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT, [ECMAScript heartbeat support])
+else
+	CONFIG_ECMASCRIPT_SMJS_HEARTBEAT=no
+fi
+AC_SUBST(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT)
+
+

 # ===================================================================
 # Optional Spidermonkey-based ECMAScript browser scripting
diff -Naur elinks-0.12pre5/Makefile.config.in elinks-0.12pre5.new/Makefile.config.in
--- elinks-0.12pre5/Makefile.config.in	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/Makefile.config.in	2012-05-05 18:58:55.000000000 +0200
@@ -117,6 +117,7 @@
 CONFIG_ECMASCRIPT = @CONFIG_ECMASCRIPT@
 CONFIG_ECMASCRIPT_SEE = @CONFIG_ECMASCRIPT_SEE@
 CONFIG_ECMASCRIPT_SMJS = @CONFIG_ECMASCRIPT_SMJS@
+CONFIG_ECMASCRIPT_SMJS_HEARTBEAT = @CONFIG_ECMASCRIPT_SMJS@
 CONFIG_EXMODE = @CONFIG_EXMODE@
 CONFIG_FASTMEM = @CONFIG_FASTMEM@
 CONFIG_FINGER = @CONFIG_FINGER@
diff -Naur elinks-0.12pre5/src/ecmascript/ecmascript.h elinks-0.12pre5.new/src/ecmascript/ecmascript.h
--- elinks-0.12pre5/src/ecmascript/ecmascript.h	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/ecmascript/ecmascript.h	2012-05-05 19:05:39.000000000 +0200
@@ -32,7 +32,11 @@
 	/* The code evaluated by setTimeout() */
 	struct string code;

-	time_t exec_start;
+#if defined(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT)
+	struct heartbeat *heartbeat;
+#elif defined(HAVE_JS_SETBRANCHCALLBACK)
+ 	time_t exec_start;
+#endif

 	/* This is a cross-rerenderings accumulator of
 	 * @document.onload_snippets (see its description for juicy details).
diff -Naur elinks-0.12pre5/src/ecmascript/spidermonkey/document.c elinks-0.12pre5.new/src/ecmascript/spidermonkey/document.c
--- elinks-0.12pre5/src/ecmascript/spidermonkey/document.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/ecmascript/spidermonkey/document.c	2012-05-05 19:40:27.000000000 +0200
@@ -47,8 +47,8 @@
 #include "viewer/text/vs.h"


-static JSBool document_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
-static JSBool document_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
+static JSBool document_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp);
+static JSBool document_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp);

 /* Each @document_class object must have a @window_class parent.  */
 const JSClass document_class = {
@@ -81,7 +81,7 @@

 /* @document_class.getProperty */
 static JSBool
-document_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+document_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
 	JSObject *parent_win;	/* instance of @window_class */
 	struct view_state *vs;
@@ -104,9 +104,9 @@
 	document = doc_view->document;
 	ses = doc_view->session;

-	if (JSVAL_IS_STRING(id)) {
+	if (JSID_IS_STRING(id)) {
 		struct form *form;
-		unsigned char *string = jsval_to_string(ctx, &id);
+		unsigned char *string = jsid_to_string(ctx, &id);

 #ifdef CONFIG_COOKIES
 		if (!strcmp(string, "cookie")) {
@@ -135,12 +135,12 @@
 		return JS_TRUE;
 	}

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_TRUE;

 	undef_to_jsval(ctx, vp);

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case JSP_DOC_LOC:
 		JS_GetProperty(ctx, parent_win, "location", vp);
 		break;
@@ -188,7 +188,7 @@

 /* @document_class.setProperty */
 static JSBool
-document_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+document_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
 {
 	JSObject *parent_win;	/* instance of @window_class */
 	struct view_state *vs;
@@ -209,9 +209,9 @@
 	doc_view = vs->doc_view;
 	document = doc_view->document;

-	if (JSVAL_IS_STRING(id)) {
+	if (JSID_IS_STRING(id)) {
 #ifdef CONFIG_COOKIES
-		if (!strcmp(jsval_to_string(ctx, &id), "cookie")) {
+		if (!strcmp(jsid_to_string(ctx, &id), "cookie")) {
 			set_cookie(vs->uri, jsval_to_string(ctx, vp));
 			/* Do NOT touch our .cookie property, evil
 			 * SpiderMonkey!! */
@@ -221,10 +221,10 @@
 		return JS_TRUE;
 	}

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_TRUE;

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case JSP_DOC_TITLE:
 		mem_free_set(&document->title, stracpy(jsval_to_string(ctx, vp)));
 		print_screen_status(doc_view->session);
@@ -242,8 +242,8 @@
 	return JS_TRUE;
 }

-static JSBool document_write(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
-static JSBool document_writeln(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+static JSBool document_write(JSContext *ctx, uintN argc, jsval *rval);
+static JSBool document_writeln(JSContext *ctx, uintN argc, jsval *rval);

 const spidermonkeyFunctionSpec document_funcs[] = {
 	{ "write",		document_write,		1 },
@@ -252,12 +252,13 @@
 };

 static JSBool
-document_write_do(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv,
-                  jsval *rval, int newline)
-{
-	struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx);
-	struct string *ret = interpreter->ret;
-
+document_write_do(JSContext *ctx, uintN argc, jsval *rval, int newline)
+ {
+	jsval val;
+ 	struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx);
+ 	struct string *ret = interpreter->ret;
+	jsval *argv = JS_ARGV(ctx, rval);
+
 	if (argc >= 1 && ret) {
 		int i = 0;

@@ -281,22 +282,23 @@
 	set_led_value(interpreter->vs->doc_view->session->status.ecmascript_led, 'J');
 #endif

-	boolean_to_jsval(ctx, rval, 0);
+	boolean_to_jsval(ctx, &val, 0);
+	JS_SET_RVAL(ctx, rval, val);

 	return JS_TRUE;
 }

 /* @document_funcs{"write"} */
 static JSBool
-document_write(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+document_write(JSContext *ctx, uintN argc, jsval *rval)
 {

-	return document_write_do(ctx, obj, argc, argv, rval, 0);
+	return document_write_do(ctx, argc, rval, 0);
 }

 /* @document_funcs{"writeln"} */
 static JSBool
-document_writeln(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+document_writeln(JSContext *ctx, uintN argc, jsval *rval)
 {
-	return document_write_do(ctx, obj, argc, argv, rval, 1);
+	return document_write_do(ctx, argc, rval, 1);
 }
diff -Naur elinks-0.12pre5/src/ecmascript/spidermonkey/form.c elinks-0.12pre5.new/src/ecmascript/spidermonkey/form.c
--- elinks-0.12pre5/src/ecmascript/spidermonkey/form.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/ecmascript/spidermonkey/form.c	2012-05-06 14:48:01.000000000 +0200
@@ -55,8 +55,8 @@
  * HTMLInputElement. The difference could be spotted only by some clever tricky
  * JS code, but I hope it doesn't matter anywhere. --pasky */

-static JSBool input_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
-static JSBool input_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
+static JSBool input_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp);
+static JSBool input_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp);
 static void input_finalize(JSContext *ctx, JSObject *obj);

 /* Each @input_class object must have a @form_class parent.  */
@@ -116,10 +116,10 @@
 	{ NULL }
 };

-static JSBool input_blur(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
-static JSBool input_click(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
-static JSBool input_focus(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
-static JSBool input_select(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+static JSBool input_blur(JSContext *ctx, uintN argc, jsval *rval);
+static JSBool input_click(JSContext *ctx, uintN argc, jsval *rval);
+static JSBool input_focus(JSContext *ctx, uintN argc, jsval *rval);
+static JSBool input_select(JSContext *ctx, uintN argc, jsval *rval);

 static const spidermonkeyFunctionSpec input_funcs[] = {
 	{ "blur",	input_blur,	0 },
@@ -150,7 +150,7 @@

 /* @input_class.getProperty */
 static JSBool
-input_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+input_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
 	JSObject *parent_form;	/* instance of @form_class */
 	JSObject *parent_doc;	/* instance of @document_class */
@@ -189,7 +189,7 @@
 	assert(fc);
 	assert(fc->form && fs);

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_TRUE;

 	linknum = get_form_control_link(document, fc);
@@ -198,7 +198,7 @@

 	undef_to_jsval(ctx, vp);

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case JSP_INPUT_ACCESSKEY:
 	{
 		JSString *keystr;
@@ -301,7 +301,7 @@

 /* @input_class.setProperty */
 static JSBool
-input_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+input_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
 {
 	JSObject *parent_form;	/* instance of @form_class */
 	JSObject *parent_doc;	/* instance of @document_class */
@@ -341,14 +341,14 @@
 	assert(fc);
 	assert(fc->form && fs);

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_TRUE;

 	linknum = get_form_control_link(document, fc);
 	/* Hiddens have no link. */
 	if (linknum >= 0) link = &document->links[linknum];

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case JSP_INPUT_ACCESSKEY:
 		accesskey = jsval_to_accesskey(ctx, vp);
 		if (accesskey == UCS_NO_CHAR)
@@ -422,7 +422,7 @@

 /* @input_funcs{"blur"} */
 static JSBool
-input_blur(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+input_blur(JSContext *ctx, uintN argc, jsval *rval)
 {
 	/* We are a text-mode browser and there *always* has to be something
 	 * selected.  So we do nothing for now. (That was easy.) */
@@ -431,11 +431,14 @@

 /* @input_funcs{"click"} */
 static JSBool
-input_click(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+input_click(JSContext *ctx, uintN argc, jsval *rval)
 {
+  	jsval val;
 	JSObject *parent_form;	/* instance of @form_class */
 	JSObject *parent_doc;	/* instance of @document_class */
 	JSObject *parent_win;	/* instance of @window_class */
+	JSObject *obj = JS_THIS_OBJECT(ctx, rval);
+	jsval *argv = JS_ARGV(ctx, rval);
 	struct view_state *vs;
 	struct document_view *doc_view;
 	struct document *document;
@@ -479,17 +482,21 @@
 	else
 		print_screen_status(ses);

-	boolean_to_jsval(ctx, rval, 0);
+	boolean_to_jsval(ctx, &val, 0);
+	JS_SET_RVAL(ctx, rval, val);
 	return JS_TRUE;
 }

 /* @input_funcs{"focus"} */
 static JSBool
-input_focus(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
-{
+input_focus(JSContext *ctx, uintN argc, jsval *rval)
+ {
+	jsval val;
 	JSObject *parent_form;	/* instance of @form_class */
 	JSObject *parent_doc;	/* instance of @document_class */
 	JSObject *parent_win;	/* instance of @window_class */
+	JSObject *obj = JS_THIS_OBJECT(ctx, rval);
+	jsval *argv = JS_ARGV(ctx, rval);
 	struct view_state *vs;
 	struct document_view *doc_view;
 	struct document *document;
@@ -528,13 +535,14 @@

 	jump_to_link_number(ses, doc_view, linknum);

-	boolean_to_jsval(ctx, rval, 0);
+	boolean_to_jsval(ctx, &val, 0);
+	JS_SET_RVAL(ctx, rval, val);
 	return JS_TRUE;
 }

 /* @input_funcs{"select"} */
 static JSBool
-input_select(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+input_select(JSContext *ctx, uintN argc, jsval *rval)
 {
 	/* We support no text selecting yet.  So we do nothing for now.
 	 * (That was easy, too.) */
@@ -662,19 +670,21 @@


 static struct form_view *form_get_form_view(JSContext *ctx, JSObject *jsform, jsval *argv);
-static JSBool form_elements_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
+static JSBool form_elements_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp);

 /* Each @form_elements_class object must have a @form_class parent.  */
 static const JSClass form_elements_class = {
 	"elements",
 	JSCLASS_HAS_PRIVATE,
 	JS_PropertyStub, JS_PropertyStub,
-	form_elements_get_property, JS_PropertyStub,
+	form_elements_get_property, JS_StrictPropertyStub,
 	JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
 };

-static JSBool form_elements_item(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
-static JSBool form_elements_namedItem(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+static JSBool form_elements_item2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+static JSBool form_elements_namedItem2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+static JSBool form_elements_item(JSContext *ctx, uintN argc, jsval *rval);
+static JSBool form_elements_namedItem(JSContext *ctx, uintN argc, jsval *rval);

 static const spidermonkeyFunctionSpec form_elements_funcs[] = {
 	{ "item",		form_elements_item,		1 },
@@ -696,8 +706,9 @@

 /* @form_elements_class.getProperty */
 static JSBool
-form_elements_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+form_elements_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
+	jsval idval;
 	JSObject *parent_form;	/* instance of @form_class */
 	JSObject *parent_doc;	/* instance of @document_class */
 	JSObject *parent_win;	/* instance of @window_class */
@@ -730,32 +741,46 @@
 	if (!form_view) return JS_FALSE; /* detached */
 	form = find_form_by_form_view(document, form_view);

-	if (JSVAL_IS_STRING(id)) {
-		form_elements_namedItem(ctx, obj, 1, &id, vp);
+	if (JSID_IS_STRING(id)) {
+		JS_IdToValue(ctx, id, &idval);
+		form_elements_namedItem2(ctx, obj, 1, &idval, vp);
 		return JS_TRUE;
 	}

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_TRUE;

 	undef_to_jsval(ctx, vp);

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case JSP_FORM_ELEMENTS_LENGTH:
 		int_to_jsval(ctx, vp, list_size(&form->items));
 		break;
 	default:
 		/* Array index. */
-		form_elements_item(ctx, obj, 1, &id, vp);
-		break;
+		JS_IdToValue(ctx, id, &idval);
+		form_elements_item2(ctx, obj, 1, &idval, vp);		break;
 	}

 	return JS_TRUE;
 }

+static JSBool
+form_elements_item(JSContext *ctx, uintN argc, jsval *rval)
+{
+	jsval val;
+	JSObject *obj = JS_THIS_OBJECT(ctx, rval);
+	jsval *argv = JS_ARGV(ctx, rval);
+	JSBool ret = form_elements_item2(ctx, obj, argc, argv, &val);
+
+	JS_SET_RVAL(ctx, rval, val);
+	return ret;
+}
+
+
 /* @form_elements_funcs{"item"} */
 static JSBool
-form_elements_item(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+form_elements_item2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
 	JSObject *parent_form;	/* instance of @form_class */
 	JSObject *parent_doc;	/* instance of @document_class */
@@ -813,9 +838,21 @@
 	return JS_TRUE;
 }

+static JSBool
+form_elements_namedItem(JSContext *ctx, uintN argc, jsval *rval)
+{
+	jsval val;
+	JSObject *obj = JS_THIS_OBJECT(ctx, rval);
+	jsval *argv = JS_ARGV(ctx, rval);
+	JSBool ret = form_elements_namedItem2(ctx, obj, argc, argv, &val);
+
+	JS_SET_RVAL(ctx, rval, val);
+	return ret;
+}
+
 /* @form_elements_funcs{"namedItem"} */
 static JSBool
-form_elements_namedItem(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+form_elements_namedItem2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
 	JSObject *parent_form;	/* instance of @form_class */
 	JSObject *parent_doc;	/* instance of @document_class */
@@ -876,8 +913,8 @@



-static JSBool form_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
-static JSBool form_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
+static JSBool form_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp);
+static JSBool form_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp);
 static void form_finalize(JSContext *ctx, JSObject *obj);

 /* Each @form_class object must have a @document_class parent.  */
@@ -914,8 +951,8 @@
 	{ NULL }
 };

-static JSBool form_reset(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
-static JSBool form_submit(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+static JSBool form_reset(JSContext *ctx, uintN argc, jsval *rval);
+static JSBool form_submit(JSContext *ctx, uintN argc, jsval *rval);

 static const spidermonkeyFunctionSpec form_funcs[] = {
 	{ "reset",	form_reset,	0 },
@@ -940,7 +977,7 @@

 /* @form_class.getProperty */
 static JSBool
-form_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+form_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
 	/* DBG("doc %p %s\n", parent_doc, JS_GetStringBytes(JS_ValueToString(ctx, OBJECT_TO_JSVAL(parent_doc)))); */
 	JSObject *parent_doc;	/* instance of @document_class */
@@ -971,11 +1008,11 @@

 	assert(form);

-	if (JSVAL_IS_STRING(id)) {
+	if (JSID_IS_STRING(id)) {
 		struct form_control *fc;
 		unsigned char *string;

-		string = jsval_to_string(ctx, &id);
+		string = jsid_to_string(ctx, &id);
 		foreach (fc, form->items) {
 			JSObject *fcobj = NULL;
 			struct form_state *fs;
@@ -996,12 +1033,12 @@
 		return JS_TRUE;
 	}

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_TRUE;

 	undef_to_jsval(ctx, vp);

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case JSP_FORM_ACTION:
 		string_to_jsval(ctx, vp, form->action);
 		break;
@@ -1076,7 +1113,7 @@

 /* @form_class.setProperty */
 static JSBool
-form_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+form_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
 {
 	JSObject *parent_doc;	/* instance of @document_class */
 	JSObject *parent_win;	/* instance of @window_class */
@@ -1107,10 +1144,10 @@

 	assert(form);

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_TRUE;

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case JSP_FORM_ACTION:
 		string = stracpy(jsval_to_string(ctx, vp));
 		if (form->action) {
@@ -1162,10 +1199,13 @@

 /* @form_funcs{"reset"} */
 static JSBool
-form_reset(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+form_reset(JSContext *ctx, uintN argc, jsval *rval)
 {
+  	jsval val;
 	JSObject *parent_doc;	/* instance of @document_class */
 	JSObject *parent_win;	/* instance of @window_class */
+	JSObject *obj = JS_THIS_OBJECT(ctx, rval);
+	jsval *argv = JS_ARGV(ctx, rval);
 	struct view_state *vs;
 	struct document_view *doc_view;
 	struct form_view *fv;
@@ -1191,17 +1231,21 @@
 	do_reset_form(doc_view, form);
 	draw_forms(doc_view->session->tab->term, doc_view);

-	boolean_to_jsval(ctx, rval, 0);
+	boolean_to_jsval(ctx, &val, 0);
+	JS_SET_RVAL(ctx, rval, val);

 	return JS_TRUE;
 }

 /* @form_funcs{"submit"} */
 static JSBool
-form_submit(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+form_submit(JSContext *ctx, uintN argc, jsval *rval)
 {
+  	jsval val;
 	JSObject *parent_doc;	/* instance of @document_class */
 	JSObject *parent_win;	/* instance of @window_class */
+	JSObject *obj = JS_THIS_OBJECT(ctx, rval);
+	jsval *argv = JS_ARGV(ctx, rval);
 	struct view_state *vs;
 	struct document_view *doc_view;
 	struct session *ses;
@@ -1227,7 +1271,8 @@
 	assert(form);
 	submit_given_form(ses, doc_view, form, 0);

-	boolean_to_jsval(ctx, rval, 0);
+	boolean_to_jsval(ctx, &val, 0);
+	JS_SET_RVAL(ctx, rval, val);

 	return JS_TRUE;
 }
@@ -1308,19 +1353,20 @@
 }


-static JSBool forms_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
+static JSBool forms_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp);

 /* Each @forms_class object must have a @document_class parent.  */
 const JSClass forms_class = {
 	"forms",
 	JSCLASS_HAS_PRIVATE,
 	JS_PropertyStub, JS_PropertyStub,
-	forms_get_property, JS_PropertyStub,
+	forms_get_property, JS_StrictPropertyStub,
 	JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
 };

-static JSBool forms_item(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
-static JSBool forms_namedItem(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+static JSBool forms_item(JSContext *ctx, uintN argc, jsval *rval);
+static JSBool forms_item2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+static JSBool forms_namedItem(JSContext *ctx, uintN argc, jsval *rval);

 const spidermonkeyFunctionSpec forms_funcs[] = {
 	{ "item",		forms_item,		1 },
@@ -1365,8 +1411,9 @@

 /* @forms_class.getProperty */
 static JSBool
-forms_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+forms_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
+  	jsval idval;
 	JSObject *parent_doc;	/* instance of @document_class */
 	JSObject *parent_win;	/* instance of @window_class */
 	struct view_state *vs;
@@ -1390,36 +1437,50 @@
 	doc_view = vs->doc_view;
 	document = doc_view->document;

-	if (JSVAL_IS_STRING(id)) {
+	if (JSID_IS_STRING(id)) {
 		/* When SMJS evaluates forms.namedItem("foo"), it first
 		 * calls forms_get_property with id = JSString "namedItem"
 		 * and *vp = JSObject JSFunction forms_namedItem.
 		 * If we don't find a form whose name is id,
 		 * we must leave *vp unchanged here, to avoid
 		 * "TypeError: forms.namedItem is not a function".  */
-		find_form_by_name(ctx, parent_doc, doc_view, id, vp);
+		JS_IdToValue(ctx, id, &idval);
+		find_form_by_name(ctx, parent_doc, doc_view, idval, vp);
 		return JS_TRUE;
 	}

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_TRUE;

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case JSP_FORMS_LENGTH:
 		int_to_jsval(ctx, vp, list_size(&document->forms));
 		break;
 	default:
 		/* Array index. */
-		forms_item(ctx, obj, 1, &id, vp);
+		JS_IdToValue(ctx, id, &idval);
+		forms_item2(ctx, obj, 1, &idval, vp);
 		break;
 	}

 	return JS_TRUE;
 }

+static JSBool
+forms_item(JSContext *ctx, uintN argc, jsval *rval)
+{
+	jsval val;
+	JSObject *obj = JS_THIS_OBJECT(ctx, rval);
+	jsval *argv = JS_ARGV(ctx, rval);
+	JSBool ret = forms_item2(ctx, obj, argc, argv, &val);
+
+	JS_SET_RVAL(ctx, rval, val);
+	return ret;
+}
+
 /* @forms_funcs{"item"} */
 static JSBool
-forms_item(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+forms_item2(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
 	JSObject *parent_doc;	/* instance of @document_class */
 	JSObject *parent_win;	/* instance of @window_class */
@@ -1459,10 +1520,13 @@

 /* @forms_funcs{"namedItem"} */
 static JSBool
-forms_namedItem(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+forms_namedItem(JSContext *ctx, uintN argc, jsval *rval)
 {
+	jsval val;
 	JSObject *parent_doc;	/* instance of @document_class */
 	JSObject *parent_win;	/* instance of @window_class */
+	JSObject *obj = JS_THIS_OBJECT(ctx, rval);
+	jsval *argv = JS_ARGV(ctx, rval);
 	struct view_state *vs;
 	struct document_view *doc_view;

@@ -1481,8 +1545,9 @@
 	if (argc != 1)
 		return JS_TRUE;

-	undef_to_jsval(ctx, rval);
-	find_form_by_name(ctx, parent_doc, doc_view, argv[0], rval);
+	undef_to_jsval(ctx, &val);
+	find_form_by_name(ctx, parent_doc, doc_view, argv[0], &val);
+	JS_SET_RVAL(ctx, rval, val);
 	return JS_TRUE;
 }

@@ -1519,13 +1584,13 @@
 jsval_to_accesskey(JSContext *ctx, jsval *vp)
 {
 	size_t len;
-	const jschar *chr;
+	const char *chr;

 	/* Convert the value in place, to protect the result from GC.  */
 	if (JS_ConvertValue(ctx, *vp, JSTYPE_STRING, vp) == JS_FALSE)
 		return UCS_NO_CHAR;
-	len = JS_GetStringLength(JSVAL_TO_STRING(*vp));
-	chr = JS_GetStringChars(JSVAL_TO_STRING(*vp));
+	len = JS_GetStringEncodingLength(ctx, JSVAL_TO_STRING(*vp));
+	chr = JS_EncodeString(ctx, JSVAL_TO_STRING(*vp));

 	/* This implementation ignores extra characters in the string.  */
 	if (len < 1)
diff -Naur elinks-0.12pre5/src/ecmascript/spidermonkey/heartbeat.c elinks-0.12pre5.new/src/ecmascript/spidermonkey/heartbeat.c
--- elinks-0.12pre5/src/ecmascript/spidermonkey/heartbeat.c	1970-01-01 01:00:00.000000000 +0100
+++ elinks-0.12pre5.new/src/ecmascript/spidermonkey/heartbeat.c	2012-05-06 15:48:51.000000000 +0200
@@ -0,0 +1,126 @@
+/* The SpiderMonkey ECMAScript backend heartbeat fuctionality. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/time.h>    /* setitimer(2) */
+
+#include "elinks.h"
+
+#include "ecmascript/spidermonkey/util.h"
+
+#include "config/options.h"
+#include "document/view.h"
+#include "ecmascript/ecmascript.h"
+#include "ecmascript/spidermonkey.h"
+#include "ecmascript/spidermonkey/heartbeat.h"
+#include "osdep/signals.h"
+#include "session/session.h"
+#include "util/lists.h"
+#include "util/math.h"   /* int_upper_bound */
+#include "util/memory.h"
+#include "viewer/text/vs.h"
+
+
+
+static INIT_LIST_OF(struct heartbeat, heartbeats);
+
+static struct itimerval heartbeat_timer = { { 1, 0 }, { 1, 0 } };
+
+
+/* This callback is installed by JS_SetOperationCallback and triggered
+ * by JS_TriggerOperationCallback in the heartbeat code below.  Returning
+ * JS_FALSE terminates script execution immediately. */
+JSBool
+heartbeat_callback(JSContext *ctx)
+{
+        return JS_FALSE;
+}
+
+/* Callback for SIGVTALRM.  Go through all heartbeats, decrease each
+ * one's TTL, and call JS_TriggerOperationCallback if a heartbeat's TTL
+ * goes to 0. */
+static void
+check_heartbeats(void *data)
+{
+        struct heartbeat *hb;
+
+        foreach (hb, heartbeats) {
+		assert(hb->interpreter);
+
+                --hb->ttl;
+
+                if (hb->ttl <= 0) {
+			if (hb->interpreter->vs
+			    && hb->interpreter->vs->doc_view
+			    && hb->interpreter->vs->doc_view->session
+			    && hb->interpreter->vs->doc_view->session->tab
+			    && hb->interpreter->vs->doc_view->session->tab->term) {
+				struct session *ses = hb->interpreter->vs->doc_view->session;
+				struct terminal *term = ses->tab->term;
+				int max_exec_time = get_opt_int("ecmascript.max_exec_time");
+
+				ecmascript_timeout_dialog(term, max_exec_time);
+			}
+
+                        JS_TriggerOperationCallback(hb->interpreter->backend_data);
+                }
+        }
+
+        install_signal_handler(SIGVTALRM, check_heartbeats, NULL, 1);
+}
+
+/* Create a new heartbeat for the given interpreter. */
+struct heartbeat *
+add_heartbeat(struct ecmascript_interpreter *interpreter)
+{
+	struct session *ses;
+        struct heartbeat *hb;
+
+	assert(interpreter);
+
+	if (!interpreter->vs || !interpreter->vs->doc_view)
+		ses = NULL;
+	else
+		ses = interpreter->vs->doc_view->session;
+
+        hb = mem_alloc(sizeof(struct heartbeat));
+        if (!hb) return NULL;
+
+        hb->ttl = get_opt_int("ecmascript.max_exec_time");
+        hb->interpreter = interpreter;
+
+        add_to_list(heartbeats, hb);
+
+        /* Update the heartbeat timer. */
+        if (list_is_singleton(*hb)) {
+                heartbeat_timer.it_value.tv_sec = 1;
+                setitimer(ITIMER_VIRTUAL, &heartbeat_timer, NULL);
+        }
+
+        /* We install the handler every call to add_heartbeat instead of only on
+         * module initialisation because other code may set other handlers for
+         * the signal.  */
+        install_signal_handler(SIGVTALRM, check_heartbeats, NULL, 1);
+
+        return hb;
+}
+
+/* Destroy the given heartbeat. */
+void
+done_heartbeat(struct heartbeat *hb)
+{
+	if (!hb) return; /* add_heartbeat returned NULL */
+	assert(hb->interpreter);
+
+        /* Stop the heartbeat timer if this heartbeat is the only one. */
+        if (list_is_singleton(*hb)) {
+                heartbeat_timer.it_value.tv_sec = 0;
+                setitimer(ITIMER_VIRTUAL, &heartbeat_timer, NULL);
+        }
+
+        del_from_list(hb);
+        hb->interpreter->heartbeat = NULL;
+        mem_free(hb);
+}
diff -Naur elinks-0.12pre5/src/ecmascript/spidermonkey/heartbeat.h elinks-0.12pre5.new/src/ecmascript/spidermonkey/heartbeat.h
--- elinks-0.12pre5/src/ecmascript/spidermonkey/heartbeat.h	1970-01-01 01:00:00.000000000 +0100
+++ elinks-0.12pre5.new/src/ecmascript/spidermonkey/heartbeat.h	2012-05-05 19:22:33.000000000 +0200
@@ -0,0 +1,24 @@
+#ifndef EL__ECMASCRIPT_SPIDERMONKEY_HEARTBEAT_H
+#define EL__ECMASCRIPT_SPIDERMONKEY_HEARTBEAT_H
+
+#include "ecmascript/spidermonkey/util.h"
+
+#include "ecmascript/spidermonkey.h"
+
+struct heartbeat {
+        LIST_HEAD(struct heartbeat);
+
+        int ttl; /* Time to live.  This value is assigned when the
+                  * script begins execution and is decremented every
+                  * second.  When it reaches 0, script execution is
+                  * terminated. */
+
+        struct ecmascript_interpreter *interpreter;
+};
+
+struct heartbeat *add_heartbeat(struct ecmascript_interpreter *interpreter);
+void done_heartbeat(struct heartbeat *hb);
+
+JSBool heartbeat_callback(JSContext *ctx);
+
+#endif
diff -Naur elinks-0.12pre5/src/ecmascript/spidermonkey/location.c elinks-0.12pre5.new/src/ecmascript/spidermonkey/location.c
--- elinks-0.12pre5/src/ecmascript/spidermonkey/location.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/ecmascript/spidermonkey/location.c	2012-05-06 15:48:05.000000000 +0200
@@ -45,15 +45,15 @@
 #include "viewer/text/vs.h"


-static JSBool history_back(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
-static JSBool history_forward(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
-static JSBool history_go(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+static JSBool history_back(JSContext *ctx, uintN argc, jsval *rval);
+static JSBool history_forward(JSContext *ctx, uintN argc, jsval *rval);
+static JSBool history_go(JSContext *ctx, uintN argc, jsval *rval);

 const JSClass history_class = {
 	"history",
 	JSCLASS_HAS_PRIVATE,
 	JS_PropertyStub, JS_PropertyStub,
-	JS_PropertyStub, JS_PropertyStub,
+	JS_PropertyStub, JS_StrictPropertyStub,
 	JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
 };

@@ -66,7 +66,7 @@

 /* @history_funcs{"back"} */
 static JSBool
-history_back(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+history_back(JSContext *ctx, uintN argc, jsval *rval)
 {
 	struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx);
 	struct document_view *doc_view = interpreter->vs->doc_view;
@@ -78,12 +78,13 @@
  * and return non zero for <a href="javascript:history.back()"> to prevent
  * "calculating" new link. Returned value 2 is changed to 0 in function
  * spidermonkey_eval_boolback */
+	JS_SET_RVAL(ctx, rval, JSVAL_NULL);
 	return 2;
 }

 /* @history_funcs{"forward"} */
 static JSBool
-history_forward(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+history_forward(JSContext *ctx, uintN argc, jsval *rval)
 {
 	struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx);
 	struct document_view *doc_view = interpreter->vs->doc_view;
@@ -91,16 +92,18 @@

 	go_unback(ses);

+	JS_SET_RVAL(ctx, rval, JSVAL_NULL);
 	return 2;
 }

 /* @history_funcs{"go"} */
 static JSBool
-history_go(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+history_go(JSContext *ctx, uintN argc, jsval *rval)
 {
 	struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx);
 	struct document_view *doc_view = interpreter->vs->doc_view;
 	struct session *ses = doc_view->session;
+	jsval *argv = JS_ARGV(ctx, rval);
 	int index;
 	struct location *loc;

@@ -120,12 +123,13 @@
 		index += index > 0 ? -1 : 1;
 	}

+	JS_SET_RVAL(ctx, rval, JSVAL_NULL);
 	return 2;
 }


-static JSBool location_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
-static JSBool location_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
+static JSBool location_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp);
+static JSBool location_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp);

 /* Each @location_class object must have a @window_class parent.  */
 const JSClass location_class = {
@@ -150,7 +154,7 @@

 /* @location_class.getProperty */
 static JSBool
-location_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+location_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
 	JSObject *parent_win;	/* instance of @window_class */
 	struct view_state *vs;
@@ -167,12 +171,12 @@
 	vs = JS_GetInstancePrivate(ctx, parent_win,
 				   (JSClass *) &window_class, NULL);

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_TRUE;

 	undef_to_jsval(ctx, vp);

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case JSP_LOC_HREF:
 		astring_to_jsval(ctx, vp, get_uri_string(vs->uri, URI_ORIGINAL));
 		break;
@@ -191,7 +195,7 @@

 /* @location_class.setProperty */
 static JSBool
-location_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+location_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
 {
 	JSObject *parent_win;	/* instance of @window_class */
 	struct view_state *vs;
@@ -210,10 +214,10 @@
 				   (JSClass *) &window_class, NULL);
 	doc_view = vs->doc_view;

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_TRUE;

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case JSP_LOC_HREF:
 		location_goto(doc_view, jsval_to_string(ctx, vp));
 		break;
@@ -222,7 +226,7 @@
 	return JS_TRUE;
 }

-static JSBool location_toString(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+static JSBool location_toString(JSContext *ctx, uintN argc, jsval *rval);

 const spidermonkeyFunctionSpec location_funcs[] = {
 	{ "toString",		location_toString,	0 },
@@ -232,9 +236,14 @@

 /* @location_funcs{"toString"}, @location_funcs{"toLocaleString"} */
 static JSBool
-location_toString(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+location_toString(JSContext *ctx, uintN argc, jsval *rval)
 {
-	return JS_GetProperty(ctx, obj, "href", rval);
+	jsval val;
+	JSObject *obj = JS_THIS_OBJECT(ctx, rval);
+	JSBool ret = JS_GetProperty(ctx, obj, "href", &val);
+
+	JS_SET_RVAL(ctx, rval, val);
+	return ret;
 }

 struct delayed_goto {
diff -Naur elinks-0.12pre5/src/ecmascript/spidermonkey/Makefile elinks-0.12pre5.new/src/ecmascript/spidermonkey/Makefile
--- elinks-0.12pre5/src/ecmascript/spidermonkey/Makefile	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/ecmascript/spidermonkey/Makefile	2012-05-05 19:16:59.000000000 +0200
@@ -2,6 +2,8 @@
 include $(top_builddir)/Makefile.config
 INCLUDES += $(SPIDERMONKEY_CFLAGS)

+OBJS-$(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT) += heartbeat.o
+
 OBJS = document.o form.o location.o navigator.o unibar.o window.o

 include $(top_srcdir)/Makefile.lib
diff -Naur elinks-0.12pre5/src/ecmascript/spidermonkey/navigator.c elinks-0.12pre5.new/src/ecmascript/spidermonkey/navigator.c
--- elinks-0.12pre5/src/ecmascript/spidermonkey/navigator.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/ecmascript/spidermonkey/navigator.c	2012-05-06 14:56:52.000000000 +0200
@@ -44,13 +44,13 @@
 #include "viewer/text/vs.h"


-static JSBool navigator_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
+static JSBool navigator_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp);

 const JSClass navigator_class = {
 	"navigator",
 	JSCLASS_HAS_PRIVATE,
 	JS_PropertyStub, JS_PropertyStub,
-	navigator_get_property, JS_PropertyStub,
+	navigator_get_property, JS_StrictPropertyStub,
 	JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
 };

@@ -81,14 +81,14 @@

 /* @navigator_class.getProperty */
 static JSBool
-navigator_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+navigator_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_TRUE;

 	undef_to_jsval(ctx, vp);

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case JSP_NAVIGATOR_APP_CODENAME:
 		string_to_jsval(ctx, vp, "Mozilla"); /* More like a constant nowadays. */
 		break;
diff -Naur elinks-0.12pre5/src/ecmascript/spidermonkey/unibar.c elinks-0.12pre5.new/src/ecmascript/spidermonkey/unibar.c
--- elinks-0.12pre5/src/ecmascript/spidermonkey/unibar.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/ecmascript/spidermonkey/unibar.c	2012-05-06 14:59:28.000000000 +0200
@@ -45,8 +45,8 @@
 #include "viewer/text/vs.h"


-static JSBool unibar_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
-static JSBool unibar_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
+static JSBool unibar_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp);
+static JSBool unibar_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp);

 /* Each @menubar_class object must have a @window_class parent.  */
 const JSClass menubar_class = {
@@ -80,7 +80,7 @@

 /* @menubar_class.getProperty, @statusbar_class.getProperty */
 static JSBool
-unibar_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+unibar_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
 	JSObject *parent_win;	/* instance of @window_class */
 	struct view_state *vs;
@@ -104,10 +104,10 @@
 	status = &doc_view->session->status;
 	bar = JS_GetPrivate(ctx, obj); /* from @menubar_class or @statusbar_class */

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_TRUE;

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case JSP_UNIBAR_VISIBLE:
 #define unibar_fetch(bar) \
 	boolean_to_jsval(ctx, vp, status->force_show_##bar##_bar >= 0 \
@@ -139,7 +139,7 @@

 /* @menubar_class.setProperty, @statusbar_class.setProperty */
 static JSBool
-unibar_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+unibar_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
 {
 	JSObject *parent_win;	/* instance of @window_class */
 	struct view_state *vs;
@@ -163,10 +163,10 @@
 	status = &doc_view->session->status;
 	bar = JS_GetPrivate(ctx, obj); /* from @menubar_class or @statusbar_class */

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_TRUE;

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case JSP_UNIBAR_VISIBLE:
 		switch (*bar) {
 		case 's':
diff -Naur elinks-0.12pre5/src/ecmascript/spidermonkey/window.c elinks-0.12pre5.new/src/ecmascript/spidermonkey/window.c
--- elinks-0.12pre5/src/ecmascript/spidermonkey/window.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/ecmascript/spidermonkey/window.c	2012-05-06 15:07:41.000000000 +0200
@@ -44,12 +44,12 @@
 #include "viewer/text/vs.h"


-static JSBool window_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
-static JSBool window_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
+static JSBool window_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp);
+static JSBool window_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp);

 const JSClass window_class = {
 	"window",
-	JSCLASS_HAS_PRIVATE,	/* struct view_state * */
+	JSCLASS_HAS_PRIVATE | JSCLASS_GLOBAL_FLAGS,	/* struct view_state * */
 	JS_PropertyStub, JS_PropertyStub,
 	window_get_property, window_set_property,
 	JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
@@ -122,7 +122,7 @@

 /* @window_class.getProperty */
 static JSBool
-window_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+window_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
 	struct view_state *vs;

@@ -138,11 +138,11 @@
 	 * location is then evaluated in string context, toString()
 	 * is called which we overrode for that class below, so
 	 * everything's fine. */
-	if (JSVAL_IS_STRING(id)) {
+	if (JSID_IS_STRING(id)) {
 		struct document_view *doc_view = vs->doc_view;
 		JSObject *obj;

-		obj = try_resolve_frame(doc_view, jsval_to_string(ctx, &id));
+		obj = try_resolve_frame(doc_view, jsid_to_string(ctx, &id));
 		/* TODO: Try other lookups (mainly element lookup) until
 		 * something yields data. */
 		if (obj) {
@@ -151,12 +151,12 @@
 		return JS_TRUE;
 	}

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_TRUE;

 	undef_to_jsval(ctx, vp);

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case JSP_WIN_CLOSED:
 		/* TODO: It will be a major PITA to implement this properly.
 		 * Well, perhaps not so much if we introduce reference tracking
@@ -254,7 +254,7 @@

 /* @window_class.setProperty */
 static JSBool
-window_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+window_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
 {
 	struct view_state *vs;

@@ -266,8 +266,8 @@

 	vs = JS_GetInstancePrivate(ctx, obj, (JSClass *) &window_class, NULL);

-	if (JSVAL_IS_STRING(id)) {
-		if (!strcmp(jsval_to_string(ctx, &id), "location")) {
+	if (JSID_IS_STRING(id)) {
+		if (!strcmp(jsid_to_string(ctx, &id), "location")) {
 			struct document_view *doc_view = vs->doc_view;

 			location_goto(doc_view, jsval_to_string(ctx, vp));
@@ -278,10 +278,10 @@
 		return JS_TRUE;
 	}

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_TRUE;

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case JSP_WIN_STATUS:
 		mem_free_set(&vs->doc_view->session->status.window_status, stracpy(jsval_to_string(ctx, vp)));
 		print_screen_status(vs->doc_view->session);
@@ -298,9 +298,9 @@
 }


-static JSBool window_alert(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
-static JSBool window_open(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
-static JSBool window_setTimeout(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+static JSBool window_alert(JSContext *ctx, uintN argc, jsval *rval);
+static JSBool window_open(JSContext *ctx, uintN argc, jsval *rval);
+static JSBool window_setTimeout(JSContext *ctx, uintN argc, jsval *rval);

 const spidermonkeyFunctionSpec window_funcs[] = {
 	{ "alert",	window_alert,		1 },
@@ -311,8 +311,11 @@

 /* @window_funcs{"alert"} */
 static JSBool
-window_alert(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+window_alert(JSContext *ctx, uintN argc, jsval *rval)
 {
+	jsval val;
+	JSObject *obj = JS_THIS_OBJECT(ctx, rval);
+	jsval *argv = JS_ARGV(ctx, rval);
 	struct view_state *vs;
 	unsigned char *string;

@@ -330,14 +333,18 @@
 	info_box(vs->doc_view->session->tab->term, MSGBOX_FREE_TEXT,
 		N_("JavaScript Alert"), ALIGN_CENTER, stracpy(string));

-	undef_to_jsval(ctx, rval);
+	undef_to_jsval(ctx, &val);
+	JS_SET_RVAL(ctx, rval, val);
 	return JS_TRUE;
 }

 /* @window_funcs{"open"} */
 static JSBool
-window_open(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+window_open(JSContext *ctx, uintN argc, jsval *rval)
 {
+	jsval val;
+	JSObject *obj = JS_THIS_OBJECT(ctx, rval);
+	jsval *argv = JS_ARGV(ctx, rval);
 	struct view_state *vs;
 	struct document_view *doc_view;
 	struct session *ses;
@@ -407,7 +414,7 @@
 			deo->uri = get_uri_reference(uri);
 			deo->target = stracpy(frame);
 			register_bottom_half(delayed_goto_uri_frame, deo);
-			boolean_to_jsval(ctx, rval, 1);
+			boolean_to_jsval(ctx, &val, 1);
 			goto end;
 		}
 	}
@@ -418,7 +425,7 @@
 	    && can_open_in_new(ses->tab->term)) {
 		open_uri_in_new_window(ses, uri, NULL, ENV_ANY,
 				       CACHE_MODE_NORMAL, TASK_NONE);
-		boolean_to_jsval(ctx, rval, 1);
+		boolean_to_jsval(ctx, &val, 1);
 	} else {
 		/* When opening a new tab, we might get rerendered, losing our
 		 * context and triggerring a disaster, so postpone that. */
@@ -428,9 +435,9 @@
 			deo->ses = ses;
 			deo->uri = get_uri_reference(uri);
 			register_bottom_half(delayed_open, deo);
-			boolean_to_jsval(ctx, rval, 1);
+			boolean_to_jsval(ctx, &val, 1);
 		} else {
-			undef_to_jsval(ctx, rval);
+			undef_to_jsval(ctx, &val);
 		}
 	}

@@ -438,13 +445,15 @@
 	done_uri(uri);
 	mem_free_if(frame);

+	JS_SET_RVAL(ctx, rval, val);
 	return JS_TRUE;
 }

 /* @window_funcs{"setTimeout"} */
 static JSBool
-window_setTimeout(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+window_setTimeout(JSContext *ctx, uintN argc, jsval *rval)
 {
+	jsval *argv = JS_ARGV(ctx, rval);
 	struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx);
 	unsigned char *code;
 	int timeout;
diff -Naur elinks-0.12pre5/src/ecmascript/spidermonkey.c elinks-0.12pre5.new/src/ecmascript/spidermonkey.c
--- elinks-0.12pre5/src/ecmascript/spidermonkey.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/ecmascript/spidermonkey.c	2012-05-06 15:45:28.000000000 +0200
@@ -25,6 +25,7 @@
 #include "ecmascript/spidermonkey.h"
 #include "ecmascript/spidermonkey/document.h"
 #include "ecmascript/spidermonkey/form.h"
+#include "ecmascript/spidermonkey/heartbeat.h"
 #include "ecmascript/spidermonkey/location.h"
 #include "ecmascript/spidermonkey/navigator.h"
 #include "ecmascript/spidermonkey/unibar.h"
@@ -109,6 +110,7 @@
 	JS_ClearPendingException(ctx);
 }

+#if !defined(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT) && defined(HAVE_JS_SETBRANCHCALLBACK)
 static JSBool
 safeguard(JSContext *ctx, JSScript *script)
 {
@@ -132,6 +134,7 @@
 	interpreter->exec_start = time(NULL);
 	JS_SetBranchCallback(ctx, safeguard);
 }
+#endif


 static void
@@ -164,16 +167,14 @@
 		return NULL;
 	interpreter->backend_data = ctx;
 	JS_SetContextPrivate(ctx, interpreter);
-	/* TODO: Make JSOPTION_STRICT and JSOPTION_WERROR configurable. */
-#ifndef JSOPTION_COMPILE_N_GO
-#define JSOPTION_COMPILE_N_GO 0 /* Older SM versions don't have it. */
-#endif
-	/* XXX: JSOPTION_COMPILE_N_GO will go (will it?) when we implement
-	 * some kind of bytecode cache. (If we will ever do that.) */
-	JS_SetOptions(ctx, JSOPTION_VAROBJFIX | JSOPTION_COMPILE_N_GO);
+	JS_SetOptions(ctx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT);
+	JS_SetVersion(ctx, JSVERSION_LATEST);
 	JS_SetErrorReporter(ctx, error_reporter);
+#if defined(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT)
+	JS_SetOperationCallback(ctx, heartbeat_callback);
+#endif

-	window_obj = JS_NewObject(ctx, (JSClass *) &window_class, NULL, NULL);
+	window_obj = JS_NewCompartmentAndGlobalObject(ctx, (JSClass *) &window_class, NULL);
 	if (!window_obj) goto release_and_fail;
 	if (!JS_InitStandardClasses(ctx, window_obj)) goto release_and_fail;
 	if (!JS_DefineProperties(ctx, window_obj, (JSPropertySpec *) window_props))
@@ -263,10 +264,16 @@
 	assert(interpreter);
 	if (!js_module_init_ok) return;
 	ctx = interpreter->backend_data;
-	setup_safeguard(interpreter, ctx);
-	interpreter->ret = ret;
+#if defined(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT)
+	interpreter->heartbeat = add_heartbeat(interpreter);
+#elif defined(HAVE_JS_SETBRANCHCALLBACK)
+ 	setup_safeguard(interpreter, ctx);
+#endif	interpreter->ret = ret;
 	JS_EvaluateScript(ctx, JS_GetGlobalObject(ctx),
 	                  code->source, code->length, "", 0, &rval);
+#if defined(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT)
+	done_heartbeat(interpreter->heartbeat);
+#endif
 }


@@ -274,20 +281,28 @@
 spidermonkey_eval_stringback(struct ecmascript_interpreter *interpreter,
 			     struct string *code)
 {
+  	JSBool ret;
 	JSContext *ctx;
 	jsval rval;

 	assert(interpreter);
 	if (!js_module_init_ok) return NULL;
 	ctx = interpreter->backend_data;
-	setup_safeguard(interpreter, ctx);
 	interpreter->ret = NULL;
-	if (JS_EvaluateScript(ctx, JS_GetGlobalObject(ctx),
-			      code->source, code->length, "", 0, &rval)
-	    == JS_FALSE) {
+#if defined(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT)
+	interpreter->heartbeat = add_heartbeat(interpreter);
+#elif defined(HAVE_JS_SETBRANCHCALLBACK)
+	setup_safeguard(interpreter, ctx);
+#endif
+	ret = JS_EvaluateScript(ctx, JS_GetGlobalObject(ctx),
+	                        code->source, code->length, "", 0, &rval);
+#if defined(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT)
+	done_heartbeat(interpreter->heartbeat);
+#endif
+	if (ret == JS_FALSE) {
 		return NULL;
 	}
-	if (JSVAL_IS_VOID(rval)) {
+	if (JSVAL_IS_VOID(rval) || JSVAL_IS_NULL(rval)) {
 		/* Undefined value. */
 		return NULL;
 	}
@@ -308,14 +323,21 @@
 	assert(interpreter);
 	if (!js_module_init_ok) return 0;
 	ctx = interpreter->backend_data;
-	setup_safeguard(interpreter, ctx);
 	interpreter->ret = NULL;
 	fun = JS_CompileFunction(ctx, NULL, "", 0, NULL, code->source,
 				 code->length, "", 0);
 	if (!fun)
 		return -1;

+#if defined(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT)
+	interpreter->heartbeat = add_heartbeat(interpreter);
+#elif defined(HAVE_JS_SETBRANCHCALLBACK)
+	setup_safeguard(interpreter, ctx);
+#endif
 	ret = JS_CallFunction(ctx, NULL, fun, 0, NULL, &rval);
+#if defined(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT)
+	done_heartbeat(interpreter->heartbeat);
+#endif
 	if (ret == 2) { /* onClick="history.back()" */
 		return 0;
 	}
diff -Naur elinks-0.12pre5/src/ecmascript/spidermonkey-shared.h elinks-0.12pre5.new/src/ecmascript/spidermonkey-shared.h
--- elinks-0.12pre5/src/ecmascript/spidermonkey-shared.h	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/ecmascript/spidermonkey-shared.h	2012-05-05 19:26:58.000000000 +0200
@@ -50,6 +50,7 @@

 static void undef_to_jsval(JSContext *ctx, jsval *vp);
 static unsigned char *jsval_to_string(JSContext *ctx, jsval *vp);
+static unsigned char *jsid_to_string(JSContext *ctx, jsid *id);

 /* Inline functions */

@@ -68,7 +69,16 @@
 		return "";
 	}

-	return empty_string_or_(JS_GetStringBytes(JS_ValueToString(ctx, val)));
+	return empty_string_or_(JS_EncodeString(ctx, JS_ValueToString(ctx, val)));
 }

+static inline unsigned char *
+jsid_to_string(JSContext *ctx, jsid *id)
+{
+	jsval v;
+
+	/* TODO: check returned value */
+	JS_IdToValue(ctx, *id, &v);
+	return jsval_to_string(ctx, &v);}
+
 #endif
diff -Naur elinks-0.12pre5/src/scripting/smjs/action_object.c elinks-0.12pre5.new/src/scripting/smjs/action_object.c
--- elinks-0.12pre5/src/scripting/smjs/action_object.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/scripting/smjs/action_object.c	2012-05-06 15:14:11.000000000 +0200
@@ -40,25 +40,31 @@

 /* @action_fn_class.call */
 static JSBool
-smjs_action_fn_callback(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv,
-                        jsval *rval)
+smjs_action_fn_callback(JSContext *ctx, uintN argc, jsval *rval)
 {
+	jsval value;
+	jsval *argv = JS_ARGV(ctx, rval);
 	struct smjs_action_fn_callback_hop *hop;
 	JSObject *fn_obj;

 	assert(smjs_ctx);
 	if_assert_failed return JS_FALSE;

-	*rval = JS_FALSE;
+	value = JS_FALSE;

-	if (JS_TRUE != JS_ValueToObject(ctx, argv[-2], &fn_obj))
+	if (JS_TRUE != JS_ValueToObject(ctx, argv[-2], &fn_obj)) {
+		JS_SET_RVAL(ctx, rval, value);
 		return JS_TRUE;
+	}
 	assert(JS_InstanceOf(ctx, fn_obj, (JSClass *) &action_fn_class, NULL));
 	if_assert_failed return JS_FALSE;

 	hop = JS_GetInstancePrivate(ctx, fn_obj,
 				    (JSClass *) &action_fn_class, NULL);
-	if (!hop) return JS_TRUE;
+	if (!hop) {
+		JS_SET_RVAL(ctx, rval, value);
+		return JS_TRUE;
+	}

 	if (argc >= 1) {
 		int32 val;
@@ -70,7 +76,8 @@

 	do_action(hop->ses, hop->action_id, 1);

-	*rval = JS_TRUE;
+	value = JS_TRUE;
+	JS_SET_RVAL(ctx, rval, value);

 	return JS_TRUE;
 }
@@ -79,7 +86,7 @@
 	"action_fn",
 	JSCLASS_HAS_PRIVATE,	/* struct smjs_action_fn_callback_hop * */
 	JS_PropertyStub, JS_PropertyStub,
-	JS_PropertyStub, JS_PropertyStub,
+	JS_PropertyStub, JS_StrictPropertyStub,
 	JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
 	smjs_action_fn_finalize,
 	NULL, NULL,
@@ -124,14 +131,16 @@

 /* @action_class.getProperty */
 static JSBool
-action_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+action_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
+	jsval val;
 	JSObject *action_fn;
 	unsigned char *action_str;

 	*vp = JSVAL_NULL;

-	action_str = JS_GetStringBytes(JS_ValueToString(ctx, id));
+	JS_IdToValue(ctx, id, &val);
+	action_str = JS_EncodeString(ctx, JS_ValueToString(ctx, val));
 	if (!action_str) return JS_TRUE;

 	action_fn = smjs_get_action_fn_object(action_str);
@@ -146,7 +155,7 @@
 	"action",
 	0,
 	JS_PropertyStub, JS_PropertyStub,
-	action_get_property, JS_PropertyStub,
+	action_get_property, JS_StrictPropertyStub,
 	JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
 };

diff -Naur elinks-0.12pre5/src/scripting/smjs/bookmarks.c elinks-0.12pre5.new/src/scripting/smjs/bookmarks.c
--- elinks-0.12pre5/src/scripting/smjs/bookmarks.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/scripting/smjs/bookmarks.c	2012-05-06 15:18:12.000000000 +0200
@@ -113,29 +113,29 @@
 	unsigned char *str;

 	/* jsstring_to_utf8() might GC; protect the string to come.  */
-	if (!JS_AddNamedRoot(ctx, &jsstr, "jsval_to_bookmark_string"))
+	if (!JS_AddNamedStringRoot(ctx, &jsstr, "jsval_to_bookmark_string"))
 		return JS_FALSE;

 	jsstr = JS_ValueToString(ctx, val);
 	if (jsstr == NULL) {
-		JS_RemoveRoot(ctx, &jsstr);
+		JS_RemoveStringRoot(ctx, &jsstr);
 		return JS_FALSE;
 	}

 	str = jsstring_to_utf8(ctx, jsstr, NULL);
 	if (str == NULL) {
-		JS_RemoveRoot(ctx, &jsstr);
+		JS_RemoveStringRoot(ctx, &jsstr);
 		return JS_FALSE;
 	}

-	JS_RemoveRoot(ctx, &jsstr);
+	JS_RemoveStringRoot(ctx, &jsstr);
 	mem_free_set(result, str);
 	return JS_TRUE;
 }

 /* @bookmark_class.getProperty */
 static JSBool
-bookmark_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+bookmark_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
 	struct bookmark *bookmark;

@@ -152,10 +152,10 @@

 	undef_to_jsval(ctx, vp);

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_FALSE;

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case BOOKMARK_TITLE:
 		return bookmark_string_to_jsval(ctx, bookmark->title, vp);
 	case BOOKMARK_URL:
@@ -177,7 +177,7 @@

 /* @bookmark_class.setProperty */
 static JSBool
-bookmark_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+bookmark_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
 {
 	struct bookmark *bookmark;
 	unsigned char *title = NULL;
@@ -195,10 +195,10 @@

 	if (!bookmark) return JS_FALSE;

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_FALSE;

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case BOOKMARK_TITLE:
 		if (!jsval_to_bookmark_string(ctx, *vp, &title))
 			return JS_FALSE;
@@ -250,7 +250,7 @@

 /* @bookmark_folder_class.getProperty */
 static JSBool
-bookmark_folder_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+bookmark_folder_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
 	struct bookmark *bookmark;
 	struct bookmark *folder;
@@ -283,7 +283,7 @@
 	"bookmark_folder",
 	JSCLASS_HAS_PRIVATE,	/* struct bookmark * */
 	JS_PropertyStub, JS_PropertyStub,
-	bookmark_folder_get_property, JS_PropertyStub,
+	bookmark_folder_get_property, JS_StrictPropertyStub,
 	JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, bookmark_finalize,
 };

diff -Naur elinks-0.12pre5/src/scripting/smjs/cache_object.c elinks-0.12pre5.new/src/scripting/smjs/cache_object.c
--- elinks-0.12pre5/src/scripting/smjs/cache_object.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/scripting/smjs/cache_object.c	2012-05-06 15:21:28.000000000 +0200
@@ -40,7 +40,7 @@

 /* @cache_entry_class.getProperty */
 static JSBool
-cache_entry_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+cache_entry_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
 	struct cache_entry *cached;
 	JSBool ret;
@@ -66,9 +66,9 @@

 	undef_to_jsval(ctx, vp);

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		ret = JS_FALSE;
-	else switch (JSVAL_TO_INT(id)) {
+	else switch (JSID_TO_INT(id)) {
 	case CACHE_ENTRY_CONTENT: {
 		struct fragment *fragment = get_cache_fragment(cached);

@@ -121,7 +121,7 @@

 /* @cache_entry_class.setProperty */
 static JSBool
-cache_entry_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+cache_entry_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
 {
 	struct cache_entry *cached;
 	JSBool ret;
@@ -145,12 +145,12 @@
 	 * eventually unlock the object.  */
 	object_lock(cached);

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		ret = JS_FALSE;
-	else switch (JSVAL_TO_INT(id)) {
+	else switch (JSID_TO_INT(id)) {
 	case CACHE_ENTRY_CONTENT: {
 		JSString *jsstr = JS_ValueToString(smjs_ctx, *vp);
-		unsigned char *str = JS_GetStringBytes(jsstr);
+		unsigned char *str = JS_EncodeString(smjs_ctx, jsstr);
 		size_t len = JS_GetStringLength(jsstr);

 		add_fragment(cached, 0, str, len);
@@ -161,7 +161,7 @@
 	}
 	case CACHE_ENTRY_TYPE: {
 		JSString *jsstr = JS_ValueToString(smjs_ctx, *vp);
-		unsigned char *str = JS_GetStringBytes(jsstr);
+		unsigned char *str = JS_EncodeString(smjs_ctx, jsstr);

 		mem_free_set(&cached->content_type, stracpy(str));

@@ -170,7 +170,7 @@
 	}
 	case CACHE_ENTRY_HEAD: {
 		JSString *jsstr = JS_ValueToString(smjs_ctx, *vp);
-		unsigned char *str = JS_GetStringBytes(jsstr);
+		unsigned char *str = JS_EncodeString(smjs_ctx, jsstr);

 		mem_free_set(&cached->head, stracpy(str));

diff -Naur elinks-0.12pre5/src/scripting/smjs/core.c elinks-0.12pre5.new/src/scripting/smjs/core.c
--- elinks-0.12pre5/src/scripting/smjs/core.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/scripting/smjs/core.c	2012-05-06 15:23:37.000000000 +0200
@@ -94,11 +94,11 @@
 }

 static JSBool
-smjs_do_file_wrapper(JSContext *ctx, JSObject *obj, uintN argc,
-                     jsval *argv, jsval *rval)
+smjs_do_file_wrapper(JSContext *ctx, uintN argc, jsval *rval)
 {
+	jsval *argv = JS_ARGV(ctx, rval);
 	JSString *jsstr = JS_ValueToString(smjs_ctx, *argv);
-	unsigned char *path = JS_GetStringBytes(jsstr);
+	unsigned char *path = JS_EncodeString(smjs_ctx, jsstr);

 	if (smjs_do_file(path))
 		return JS_TRUE;
@@ -136,6 +136,10 @@
 		return;
 	}

+	JS_SetOptions(smjs_ctx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT);
+	JS_SetVersion(smjs_ctx, JSVERSION_LATEST);
+
+
 	JS_SetErrorReporter(smjs_ctx, error_reporter);

 	smjs_init_global_object();
@@ -308,7 +312,7 @@
 	struct string utf8;

 	utf16_len = JS_GetStringLength(jsstr);
-	utf16 = JS_GetStringChars(jsstr); /* stays owned by jsstr */
+	utf16 = JS_GetStringCharsZ(ctx, jsstr); /* stays owned by jsstr */
 	if (utf16 == NULL) {
 		/* JS_GetStringChars doesn't have a JSContext *
 		 * parameter so it can't report the error
diff -Naur elinks-0.12pre5/src/scripting/smjs/elinks_object.c elinks-0.12pre5.new/src/scripting/smjs/elinks_object.c
--- elinks-0.12pre5/src/scripting/smjs/elinks_object.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/scripting/smjs/elinks_object.c	2012-05-06 15:27:51.000000000 +0200
@@ -27,7 +27,7 @@


 static JSBool
-elinks_get_home(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+elinks_get_home(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
 	*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx, elinks_home));

@@ -35,7 +35,7 @@
 }

 static JSBool
-elinks_get_location(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+elinks_get_location(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
 	struct uri *uri;

@@ -51,7 +51,7 @@
 }

 static JSBool
-elinks_set_location(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+elinks_set_location(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
 	JSString *jsstr;
 	unsigned char *url;
@@ -61,7 +61,7 @@
 	jsstr = JS_ValueToString(smjs_ctx, *vp);
 	if (!jsstr) return JS_FALSE;

-	url = JS_GetStringBytes(jsstr);
+	url = JS_EncodeString(smjs_ctx, jsstr);
 	if (!url) return JS_FALSE;

 	goto_url(smjs_ses, url);
@@ -71,8 +71,10 @@

 /* @elinks_funcs{"alert"} */
 static JSBool
-elinks_alert(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+elinks_alert(JSContext *ctx, uintN argc, jsval *rval)
 {
+	jsval val;
+	jsval *argv = JS_ARGV(ctx, rval);
 	unsigned char *string;

 	if (argc != 1)
@@ -85,15 +87,18 @@
 	info_box(smjs_ses->tab->term, MSGBOX_NO_TEXT_INTL,
 	         N_("User script alert"), ALIGN_LEFT, string);

-	undef_to_jsval(ctx, rval);
+	undef_to_jsval(ctx, &val);
+	JS_SET_RVAL(ctx, rval, val);

 	return JS_TRUE;
 }

 /* @elinks_funcs{"execute"} */
 static JSBool
-elinks_execute(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+elinks_execute(JSContext *ctx, uintN argc, jsval *rval)
 {
+	jsval val;
+	jsval *argv = JS_ARGV(ctx, rval);
 	unsigned char *string;

 	if (argc != 1)
@@ -104,8 +109,9 @@
 		return JS_TRUE;

 	exec_on_terminal(smjs_ses->tab->term, string, "", TERM_EXEC_BG);
-	undef_to_jsval(ctx, rval);
-
+
+	undef_to_jsval(ctx, &val);
+	JS_SET_RVAL(ctx, rval, val);
 	return JS_TRUE;
 }

@@ -113,7 +119,7 @@
 	"elinks",
 	0,
 	JS_PropertyStub, JS_PropertyStub,
-	JS_PropertyStub, JS_PropertyStub,
+	JS_PropertyStub, JS_StrictPropertyStub,
 	JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
 };

@@ -142,7 +148,7 @@
 		return NULL;

 	if (!JS_DefineProperty(smjs_ctx, jsobj, "home", JSVAL_NULL,
-			       elinks_get_home, JS_PropertyStub,
+			       elinks_get_home, JS_StrictPropertyStub,
 			       JSPROP_ENUMERATE
 			       | JSPROP_PERMANENT
 			       | JSPROP_READONLY))
diff -Naur elinks-0.12pre5/src/scripting/smjs/global_object.c elinks-0.12pre5.new/src/scripting/smjs/global_object.c
--- elinks-0.12pre5/src/scripting/smjs/global_object.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/scripting/smjs/global_object.c	2012-05-06 15:30:11.000000000 +0200
@@ -16,9 +16,9 @@


 static const JSClass global_class = {
-	"global", 0,
-	JS_PropertyStub, JS_PropertyStub,
+	"global", JSCLASS_GLOBAL_FLAGS,
 	JS_PropertyStub, JS_PropertyStub,
+	JS_PropertyStub, JS_StrictPropertyStub,
 	JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
 };

@@ -29,7 +29,7 @@

 	assert(smjs_ctx);

-	jsobj  = JS_NewObject(smjs_ctx, (JSClass *) &global_class, NULL, NULL);
+	jsobj  = JS_NewCompartmentAndGlobalObject(smjs_ctx, (JSClass *) &global_class, NULL);

 	if (!jsobj) return NULL;

diff -Naur elinks-0.12pre5/src/scripting/smjs/globhist.c elinks-0.12pre5.new/src/scripting/smjs/globhist.c
--- elinks-0.12pre5/src/scripting/smjs/globhist.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/scripting/smjs/globhist.c	2012-05-06 15:33:38.000000000 +0200
@@ -51,7 +51,7 @@

 /* @smjs_globhist_item_class.getProperty */
 static JSBool
-smjs_globhist_item_get_property(JSContext *ctx, JSObject *obj, jsval id,
+smjs_globhist_item_get_property(JSContext *ctx, JSObject *obj, jsid id,
                                 jsval *vp)
 {
 	struct global_history_item *history_item;
@@ -70,10 +70,10 @@

 	undef_to_jsval(ctx, vp);

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_FALSE;

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case GLOBHIST_TITLE:
 		*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx,
 		                                        history_item->title));
@@ -117,7 +117,7 @@

 /* @smjs_globhist_item_class.setProperty */
 static JSBool
-smjs_globhist_item_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+smjs_globhist_item_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
 {
 	struct global_history_item *history_item;

@@ -133,13 +133,13 @@

 	if (!history_item) return JS_FALSE;

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_FALSE;

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case GLOBHIST_TITLE: {
 		JSString *jsstr = JS_ValueToString(smjs_ctx, *vp);
-		unsigned char *str = JS_GetStringBytes(jsstr);
+		unsigned char *str = JS_EncodeString(smjs_ctx, jsstr);

 		mem_free_set(&history_item->title, stracpy(str));

@@ -147,7 +147,7 @@
 	}
 	case GLOBHIST_URL: {
 		JSString *jsstr = JS_ValueToString(smjs_ctx, *vp);
-		unsigned char *str = JS_GetStringBytes(jsstr);
+		unsigned char *str = JS_EncodeString(smjs_ctx, jsstr);

 		mem_free_set(&history_item->url, stracpy(str));

@@ -201,13 +201,13 @@

 /* @smjs_globhist_class.getProperty */
 static JSBool
-smjs_globhist_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+smjs_globhist_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
 	JSObject *jsobj;
 	unsigned char *uri_string;
 	struct global_history_item *history_item;

-	uri_string = JS_GetStringBytes(JS_ValueToString(ctx, id));
+	uri_string = JS_EncodeString(ctx, JS_ValueToString(ctx, id));
 	if (!uri_string) goto ret_null;

 	history_item = get_global_history_item(uri_string);
@@ -229,7 +229,7 @@
 static const JSClass smjs_globhist_class = {
 	"global_history", 0,
 	JS_PropertyStub, JS_PropertyStub,
-	smjs_globhist_get_property, JS_PropertyStub,
+	smjs_globhist_get_property, JS_StrictPropertyStub,
 	JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
 };

diff -Naur elinks-0.12pre5/src/scripting/smjs/hooks.c elinks-0.12pre5.new/src/scripting/smjs/hooks.c
--- elinks-0.12pre5/src/scripting/smjs/hooks.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/scripting/smjs/hooks.c	2012-05-06 15:37:26.000000000 +0200
@@ -41,7 +41,7 @@
 				ret = EVENT_HOOK_STATUS_LAST;
 		} else {
 			JSString *jsstr = JS_ValueToString(smjs_ctx, rval);
-			unsigned char *str = JS_GetStringBytes(jsstr);
+			unsigned char *str = JS_EncodeString(smjs_ctx, jsstr);

 			mem_free_set(url, stracpy(str));
 		}
@@ -58,7 +58,7 @@
 	struct session *ses = va_arg(ap, struct session *);
 	struct cache_entry *cached = va_arg(ap, struct cache_entry *);
 	enum evhook_status ret = EVENT_HOOK_STATUS_NEXT;
-	JSObject *cache_entry_object, *view_state_object = JSVAL_NULL;
+	JSObject *cache_entry_object, *view_state_object = NULL;
 	jsval args[2], rval;

 	evhook_use_params(ses && cached);
diff -Naur elinks-0.12pre5/src/scripting/smjs/keybinding.c elinks-0.12pre5.new/src/scripting/smjs/keybinding.c
--- elinks-0.12pre5/src/scripting/smjs/keybinding.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/scripting/smjs/keybinding.c	2012-05-06 15:40:15.000000000 +0200
@@ -17,7 +17,7 @@

 /* @keymap_class.getProperty */
 static JSBool
-keymap_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+keymap_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
 	unsigned char *action_str;
 	const unsigned char *keystroke_str;
@@ -32,7 +32,7 @@
 	data = JS_GetInstancePrivate(ctx, obj,
 				     (JSClass *) &keymap_class, NULL);

-	keystroke_str = JS_GetStringBytes(JS_ValueToString(ctx, id));
+	keystroke_str = JS_EncodeString(ctx, JS_ValueToString(ctx, id));
 	if (!keystroke_str) goto ret_null;

 	action_str = get_action_name_from_keystroke((enum keymap_id) *data,
@@ -70,7 +70,7 @@

 /* @keymap_class.setProperty */
 static JSBool
-keymap_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+keymap_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
 {
 	int *data;
 	unsigned char *keymap_str;
@@ -90,13 +90,13 @@
 	keymap_str = get_keymap_name((enum keymap_id) *data);
 	if (!keymap_str) return JS_FALSE;

-	keystroke_str = JS_GetStringBytes(JS_ValueToString(ctx, id));
+	keystroke_str = JS_EncodeString(ctx, JS_ValueToString(ctx, id));
 	if (!keystroke_str) return JS_FALSE;

 	if (JSVAL_IS_STRING(*vp)) {
 		unsigned char *action_str;

-		action_str = JS_GetStringBytes(JS_ValueToString(ctx, *vp));
+		action_str = JS_EncodeString(ctx, JS_ValueToString(ctx, *vp));
 		if (!action_str) return JS_FALSE;

 		if (bind_do(keymap_str, keystroke_str, action_str, 0))
@@ -203,7 +203,7 @@
 	"keymaps_hash",
 	JSCLASS_HAS_PRIVATE,
 	JS_PropertyStub, JS_PropertyStub,
-	JS_PropertyStub, JS_PropertyStub,
+	JS_PropertyStub, JS_StrictPropertyStub,
 	JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
 };

diff -Naur elinks-0.12pre5/src/scripting/smjs/load_uri.c elinks-0.12pre5.new/src/scripting/smjs/load_uri.c
--- elinks-0.12pre5/src/scripting/smjs/load_uri.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/scripting/smjs/load_uri.c	2012-05-06 15:42:14.000000000 +0200
@@ -56,7 +56,7 @@
 end:
 	if (download->cached)
 		object_unlock(download->cached);
-	JS_RemoveRoot(smjs_ctx, &hop->callback);
+	JS_RemoveValueRoot(smjs_ctx, &hop->callback);
 	mem_free(download->data);
 	mem_free(download);

@@ -64,9 +64,9 @@
 }

 static JSBool
-smjs_load_uri(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv,
-              jsval *rval)
+smjs_load_uri(JSContext *ctx, uintN argc, jsval *rval)
 {
+	jsval *argv = JS_ARGV(ctx, rval);
 	struct smjs_load_uri_hop *hop;
 	struct download *download;
 	JSString *jsstr;
@@ -76,7 +76,7 @@
 	if (argc < 2) return JS_FALSE;

 	jsstr = JS_ValueToString(smjs_ctx, argv[0]);
-	uri_string = JS_GetStringBytes(jsstr);
+	uri_string = JS_EncodeString(smjs_ctx, jsstr);

 	uri = get_uri(uri_string, 0);
 	if (!uri) return JS_FALSE;
@@ -96,7 +96,7 @@

 	hop->callback = argv[1];
 	hop->ses = smjs_ses;
-	if (!JS_AddNamedRoot(smjs_ctx, &hop->callback,
+	if (!JS_AddNamedValueRoot(smjs_ctx, &hop->callback,
 			     "smjs_load_uri_hop.callback")) {
 		mem_free(hop);
 		mem_free(download);
diff -Naur elinks-0.12pre5/src/scripting/smjs/view_state_object.c elinks-0.12pre5.new/src/scripting/smjs/view_state_object.c
--- elinks-0.12pre5/src/scripting/smjs/view_state_object.c	2009-07-07 14:23:17.000000000 +0200
+++ elinks-0.12pre5.new/src/scripting/smjs/view_state_object.c	2012-05-06 15:44:24.000000000 +0200
@@ -39,7 +39,7 @@

 /* @view_state_class.getProperty */
 static JSBool
-view_state_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+view_state_get_property(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
 	struct view_state *vs;

@@ -54,10 +54,10 @@

 	undef_to_jsval(ctx, vp);

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_FALSE;

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case VIEW_STATE_PLAIN:
 		*vp = INT_TO_JSVAL(vs->plain);

@@ -80,7 +80,7 @@

 /* @view_state_class.setProperty */
 static JSBool
-view_state_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+view_state_set_property(JSContext *ctx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
 {
 	struct view_state *vs;

@@ -93,10 +93,10 @@
 	vs = JS_GetInstancePrivate(ctx, obj,
 				   (JSClass *) &view_state_class, NULL);

-	if (!JSVAL_IS_INT(id))
+	if (!JSID_IS_INT(id))
 		return JS_FALSE;

-	switch (JSVAL_TO_INT(id)) {
+	switch (JSID_TO_INT(id)) {
 	case VIEW_STATE_PLAIN: {
 		vs->plain = atol(jsval_to_string(ctx, vp));

@@ -143,7 +143,7 @@
 }

 static JSBool
-smjs_elinks_get_view_state(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
+smjs_elinks_get_view_state(JSContext *ctx, JSObject *obj, jsid id, jsval *vp)
 {
 	JSObject *vs_obj;
 	struct view_state *vs;
@@ -170,6 +170,6 @@
 		return;

 	JS_DefineProperty(smjs_ctx, smjs_elinks_object, "vs", JSVAL_NULL,
-	                smjs_elinks_get_view_state, JS_PropertyStub,
+	                smjs_elinks_get_view_state, JS_StrictPropertyStub,
 	                JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY);
 }
