diff --git a/configure.ac b/configure.ac index 47872d7ba..d71c611a9 100644 --- a/configure.ac +++ b/configure.ac @@ -612,11 +612,11 @@ case "$with_spidermonkey" in ;; esac -for package in mozjs-45; do +for package in mozjs-52; do if test -n "$CONFIG_SPIDERMONKEY"; then break else - AC_MSG_CHECKING([for SpiderMonkey (mozjs-45) in pkg-config $package]) + AC_MSG_CHECKING([for SpiderMonkey (mozjs-52) in pkg-config $package]) if $PKG_CONFIG --cflags --libs $package > /dev/null 2>&AS_MESSAGE_LOG_FD; then SPIDERMONKEY_LIBS="$($PKG_CONFIG --libs $package)" SPIDERMONKEY_CFLAGS="$($PKG_CONFIG --cflags $package)" diff --git a/meson.build b/meson.build index 777e58084..9f02215d0 100644 --- a/meson.build +++ b/meson.build @@ -271,7 +271,7 @@ if conf_data.get('CONFIG_BZIP2') endif if conf_data.get('CONFIG_ECMASCRIPT') - mozjsdeps = dependency('mozjs-45') + mozjsdeps = dependency('mozjs-52') deps += mozjsdeps endif diff --git a/src/dialogs/info.c b/src/dialogs/info.c index d4f4f7989..910d4ce23 100644 --- a/src/dialogs/info.c +++ b/src/dialogs/info.c @@ -232,7 +232,7 @@ get_resource_info(struct terminal *term, void *data) val_add(n_("%ld refreshing", "%ld refreshing", val, term)); add_to_string(&info, ".\n"); -#ifdef CONFIG_ECMASCRIPT +#ifdef CONFIG_ECMASCRIPT_SMJS add_to_string(&info, _("ECMAScript", term)); add_to_string(&info, ": "); diff --git a/src/document/renderer.c b/src/document/renderer.c index e49b4abc3..150e72aa8 100644 --- a/src/document/renderer.c +++ b/src/document/renderer.c @@ -42,7 +42,7 @@ #include "viewer/text/vs.h" -#ifdef CONFIG_ECMASCRIPT +#ifdef CONFIG_ECMASCRIPT_SMJS /** @todo XXX: This function is de facto obsolete, since we do not need to copy * snippets around anymore (we process them in one go after the document is * loaded; gradual processing was practically impossible because the snippets @@ -331,7 +331,7 @@ render_document(struct view_state *vs, struct document_view *doc_view, vs->doc_view->used = 0; /* A bit risky, but... */ vs->doc_view->vs = NULL; vs->doc_view = NULL; -#ifdef CONFIG_ECMASCRIPT +#ifdef CONFIG_ECMASCRIPT_SMJS vs->ecmascript_fragile = 1; /* And is this good? ;-) */ #endif } @@ -385,7 +385,7 @@ render_document(struct view_state *vs, struct document_view *doc_view, document->css_magic = get_document_css_magic(document); #endif } -#ifdef CONFIG_ECMASCRIPT +#ifdef CONFIG_ECMASCRIPT_SMJS if (!vs->ecmascript_fragile) assert(vs->ecmascript); if (!options->dump && !options->gradual_rerendering) { diff --git a/src/ecmascript/Makefile b/src/ecmascript/Makefile index 0e5ae66e3..69cb11227 100644 --- a/src/ecmascript/Makefile +++ b/src/ecmascript/Makefile @@ -4,7 +4,7 @@ INCLUDES += $(SPIDERMONKEY_CFLAGS) SUBDIRS-$(CONFIG_ECMASCRIPT_SMJS) += spidermonkey -OBJS-$(CONFIG_ECMASCRIPT_SMJS) += spidermonkey.o +OBJS-$(CONFIG_ECMASCRIPT_SMJS) += ecmascript.o spidermonkey.o ifeq ($(CONFIG_ECMASCRIPT_SMJS), yes) CONFIG_ANY_SPIDERMONKEY = yes @@ -16,6 +16,4 @@ endif OBJS-$(CONFIG_ANY_SPIDERMONKEY) += spidermonkey-shared.o -OBJS = ecmascript.o - include $(top_srcdir)/Makefile.lib diff --git a/src/ecmascript/ecmascript.c b/src/ecmascript/ecmascript.c index 5b48abb2b..7979f77de 100644 --- a/src/ecmascript/ecmascript.c +++ b/src/ecmascript/ecmascript.c @@ -5,6 +5,7 @@ #endif #include +#include #include "elinks.h" diff --git a/src/ecmascript/ecmascript.h b/src/ecmascript/ecmascript.h index 55273fad1..0f2a3421d 100644 --- a/src/ecmascript/ecmascript.h +++ b/src/ecmascript/ecmascript.h @@ -53,6 +53,7 @@ struct ecmascript_interpreter { * is reloaded in another tab and then you just cause the current tab * to redraw. */ unsigned int onload_snippets_cache_id; + void *ac; }; /* Why is the interpreter bound to {struct view_state} instead of {struct diff --git a/src/ecmascript/meson.build b/src/ecmascript/meson.build index af4aec2b1..d171694d8 100644 --- a/src/ecmascript/meson.build +++ b/src/ecmascript/meson.build @@ -1,7 +1,7 @@ #INCLUDES += $(SPIDERMONKEY_CFLAGS) if conf_data.get('CONFIG_ECMASCRIPT_SMJS') subdir('spidermonkey') - srcs += files('spidermonkey.c') + srcs += files('ecmascript.c', 'spidermonkey.c') endif if conf_data.get('CONFIG_ECMASCRIPT_SMJS') @@ -16,4 +16,3 @@ if CONFIG_ANY_SPIDERMONKEY srcs += files('spidermonkey-shared.c', 'empty.cpp') endif -srcs += files('ecmascript.c') diff --git a/src/ecmascript/spidermonkey-shared.c b/src/ecmascript/spidermonkey-shared.c index 8af6d5651..b65f239cd 100644 --- a/src/ecmascript/spidermonkey-shared.c +++ b/src/ecmascript/spidermonkey-shared.c @@ -10,24 +10,12 @@ #include "ecmascript/spidermonkey-shared.h" #include -/** A shared runtime used for both user scripts (scripting/smjs/) and - * scripts on web pages (ecmascript/spidermonkey/). - * - * SpiderMonkey has bugs that corrupt memory when multiple JSRuntimes - * are used: https://bugzilla.mozilla.org/show_bug.cgi?id=378918 and - * perhaps others. */ -JSRuntime *spidermonkey_runtime; - /** A JSContext that can be used in JS_SetPrivate and JS_GetPrivate - * when no better one is available. This context has no global - * object, so scripts cannot be evaluated in it. - * - * XXX: This also works around a crash on exit. SMJS will crash on - * JS_DestroyRuntime if the given runtime has never had any context - * created, which will be the case if one closes ELinks without having - * loaded any documents. */ -JSContext *spidermonkey_empty_context; +- * when no better one is available. This context has no global +- * object, so scripts cannot be evaluated in it. +- */ +JSContext *spidermonkey_empty_context; /** A reference count for ::spidermonkey_runtime so that modules using * it can be initialized and shut down in arbitrary order. */ static int spidermonkey_runtime_refcount; @@ -41,32 +29,18 @@ int spidermonkey_runtime_addref(void) { if (spidermonkey_runtime_refcount == 0) { - assert(spidermonkey_runtime == NULL); - assert(spidermonkey_empty_context == NULL); - if_assert_failed return 0; if (!JS_Init()) { return 0; } - spidermonkey_runtime = JS_NewRuntime(4L * 1024L * 1024L); - if (!spidermonkey_runtime) return 0; - - spidermonkey_empty_context = JS_NewContext(spidermonkey_runtime, - 0); + spidermonkey_empty_context = JS_NewContext(0); if (!spidermonkey_empty_context) { - /* Perhaps JS_DestroyRuntime will now crash - * because no context was created, but there's - * not much else to do. */ - JS_DestroyRuntime(spidermonkey_runtime); - spidermonkey_runtime = NULL; JS_ShutDown(); return 0; } } - assert(spidermonkey_runtime); - assert(spidermonkey_empty_context); spidermonkey_runtime_refcount++; assert(spidermonkey_runtime_refcount > 0); if_assert_failed { spidermonkey_runtime_refcount--; return 0; } @@ -80,16 +54,10 @@ void spidermonkey_runtime_release(void) { assert(spidermonkey_runtime_refcount > 0); - assert(spidermonkey_runtime); - assert(spidermonkey_empty_context); - if_assert_failed return; --spidermonkey_runtime_refcount; if (spidermonkey_runtime_refcount == 0) { JS_DestroyContext(spidermonkey_empty_context); - spidermonkey_empty_context = NULL; - JS_DestroyRuntime(spidermonkey_runtime); - spidermonkey_runtime = NULL; JS_ShutDown(); } } diff --git a/src/ecmascript/spidermonkey.c b/src/ecmascript/spidermonkey.c index a626eebb8..7ab712a4b 100644 --- a/src/ecmascript/spidermonkey.c +++ b/src/ecmascript/spidermonkey.c @@ -58,8 +58,88 @@ static int js_module_init_ok; +bool +PrintError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult, + JSErrorReport* report, bool reportWarnings) +{ + MOZ_ASSERT(report); + + /* Conditionally ignore reported warnings. */ + if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings) + return false; + + char* prefix = nullptr; + if (report->filename) + prefix = JS_smprintf("%s:", report->filename); + if (report->lineno) { + char* tmp = prefix; + prefix = JS_smprintf("%s%u:%u ", tmp ? tmp : "", report->lineno, report->column); + JS_free(cx, tmp); + } + if (JSREPORT_IS_WARNING(report->flags)) { + char* tmp = prefix; + prefix = JS_smprintf("%s%swarning: ", + tmp ? tmp : "", + JSREPORT_IS_STRICT(report->flags) ? "strict " : ""); + JS_free(cx, tmp); + } + + const char* message = toStringResult ? toStringResult.c_str() : report->message().c_str(); + + /* embedded newlines -- argh! */ + const char* ctmp; + while ((ctmp = strchr(message, '\n')) != 0) { + ctmp++; + if (prefix) + fputs(prefix, file); + fwrite(message, 1, ctmp - message, file); + message = ctmp; + } + + /* If there were no filename or lineno, the prefix might be empty */ + if (prefix) + fputs(prefix, file); + fputs(message, file); + + if (const char16_t* linebuf = report->linebuf()) { + size_t n = report->linebufLength(); + + fputs(":\n", file); + if (prefix) + fputs(prefix, file); + + for (size_t i = 0; i < n; i++) + fputc(static_cast(linebuf[i]), file); + + // linebuf usually ends with a newline. If not, add one here. + if (n == 0 || linebuf[n-1] != '\n') + fputc('\n', file); + + if (prefix) + fputs(prefix, file); + + n = report->tokenOffset(); + for (size_t i = 0, j = 0; i < n; i++) { + if (linebuf[i] == '\t') { + for (size_t k = (j + 8) & ~7; j < k; j++) + fputc('.', file); + continue; + } + fputc('.', file); + j++; + } + fputc('^', file); + } + fputc('\n', file); + fflush(file); + JS_free(cx, prefix); + return true; +} + + + static void -error_reporter(JSContext *ctx, const char *message, JSErrorReport *report) +error_reporter(JSContext *ctx, JSErrorReport *report) { struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx); struct session *ses = interpreter->vs->doc_view->session; @@ -75,6 +155,8 @@ error_reporter(JSContext *ctx, const char *message, JSErrorReport *report) term = ses->tab->term; + PrintError(ctx, stderr, JS::ConstUTF8CharsZ(), report, true/*reportWarnings*/); + #ifdef CONFIG_LEDS set_led_value(ses->status.ecmascript_led, 'J'); #endif @@ -93,7 +175,6 @@ error_reporter(JSContext *ctx, const char *message, JSErrorReport *report) strict, exception, warning, error); add_to_string(&msg, ":\n\n"); - add_to_string(&msg, message); if (report->filename) { prefix = JS_smprintf("%s:", report->filename); @@ -147,25 +228,30 @@ spidermonkey_get_interpreter(struct ecmascript_interpreter *interpreter) JSContext *ctx; JSObject *document_obj, *forms_obj, *history_obj, *location_obj, *statusbar_obj, *menubar_obj, *navigator_obj; - JSAutoCompartment *ac = NULL; assert(interpreter); if (!js_module_init_ok) return NULL; - ctx = JS_NewContext(spidermonkey_runtime, - 8192 /* Stack allocation chunk size */); +// ctx = JS_NewContext(JS::DefaultHeapMaxBytes, JS::DefaultNurseryBytes); + ctx = JS_NewContext(8L * 1024 * 1024); if (!ctx) return NULL; interpreter->backend_data = ctx; JSAutoRequest ar(ctx); JS_SetContextPrivate(ctx, interpreter); //JS_SetOptions(ctx, JSOPTION_VAROBJFIX | JS_METHODJIT); - JS_SetErrorReporter(spidermonkey_runtime, error_reporter); - JS_SetInterruptCallback(spidermonkey_runtime, heartbeat_callback); - JS::RootedObject window_obj(ctx, JS_NewGlobalObject(ctx, &window_class, NULL, JS::DontFireOnNewGlobalHook)); + JS::SetWarningReporter(ctx, error_reporter); + JS_AddInterruptCallback(ctx, heartbeat_callback); + JS::CompartmentOptions options; + + if (!JS::InitSelfHostedCode(ctx)) { + return NULL; + } + + JS::RootedObject window_obj(ctx, JS_NewGlobalObject(ctx, &window_class, NULL, JS::FireOnNewGlobalHook, options)); if (window_obj) { - ac = new JSAutoCompartment(ctx, window_obj); + interpreter->ac = new JSAutoCompartment(ctx, window_obj); } else { goto release_and_fail; } @@ -191,6 +277,7 @@ spidermonkey_get_interpreter(struct ecmascript_interpreter *interpreter) if (!document_obj) { goto release_and_fail; } + JS_SetPrivate(document_obj, interpreter->vs); forms_obj = spidermonkey_InitClass(ctx, document_obj, NULL, &forms_class, NULL, 0, @@ -266,8 +353,12 @@ spidermonkey_put_interpreter(struct ecmascript_interpreter *interpreter) assert(interpreter); if (!js_module_init_ok) return; ctx = interpreter->backend_data; + if (interpreter->ac) { + delete (JSAutoCompartment *)interpreter->ac; + } JS_DestroyContext(ctx); interpreter->backend_data = NULL; + interpreter->ac = nullptr; } diff --git a/src/ecmascript/spidermonkey/document.c b/src/ecmascript/spidermonkey/document.c index aca00e649..fe5bf51c6 100644 --- a/src/ecmascript/spidermonkey/document.c +++ b/src/ecmascript/spidermonkey/document.c @@ -50,13 +50,18 @@ static bool document_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); +JSClassOps document_ops = { + JS_PropertyStub, nullptr, + document_get_property, JS_StrictPropertyStub, + nullptr, nullptr, nullptr +}; + + /* Each @document_class object must have a @window_class parent. */ JSClass document_class = { "document", JSCLASS_HAS_PRIVATE, - JS_PropertyStub, nullptr, - document_get_property, JS_StrictPropertyStub, - nullptr, nullptr, nullptr + &document_ops }; #ifdef CONFIG_COOKIES @@ -249,16 +254,19 @@ document_set_property_title(JSContext *ctx, int argc, JS::Value *vp) { JS::CallArgs args = CallArgsFromVp(argc, vp); JS::RootedObject hobj(ctx, &args.thisv().toObject()); - JS::RootedObject parent_win(ctx, js::GetGlobalForObjectCrossCompartment(hobj)); +// JS::RootedObject parent_win(ctx, js::GetGlobalForObjectCrossCompartment(hobj)); struct view_state *vs; struct document_view *doc_view; struct document *document; - assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + assert(JS_InstanceOf(ctx, hobj, &document_class, NULL)); if_assert_failed return false; - vs = JS_GetInstancePrivate(ctx, parent_win, - &window_class, NULL); +// assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); +// if_assert_failed return false; + + vs = JS_GetInstancePrivate(ctx, hobj, + &document_class, NULL); if (!vs) { return false; } diff --git a/src/ecmascript/spidermonkey/form.c b/src/ecmascript/spidermonkey/form.c index 4ba033f88..76630191c 100644 --- a/src/ecmascript/spidermonkey/form.c +++ b/src/ecmascript/spidermonkey/form.c @@ -66,13 +66,17 @@ static bool form_set_property_target(JSContext *ctx, unsigned int argc, JS::Valu static void form_finalize(JSFreeOp *op, JSObject *obj); +static JSClassOps form_ops = { + JS_PropertyStub, nullptr, + form_get_property, JS_StrictPropertyStub, + nullptr, nullptr, nullptr, form_finalize +}; + /* Each @form_class object must have a @document_class parent. */ static JSClass form_class = { "form", JSCLASS_HAS_PRIVATE, /* struct form_view *, or NULL if detached */ - JS_PropertyStub, nullptr, - form_get_property, JS_StrictPropertyStub, - nullptr, nullptr, nullptr, form_finalize + &form_ops }; @@ -86,13 +90,17 @@ static bool input_get_property(JSContext *ctx, JS::HandleObject hobj, JS::Handle static bool input_set_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); static void input_finalize(JSFreeOp *op, JSObject *obj); +static JSClassOps input_ops = { + JS_PropertyStub, nullptr, + input_get_property, input_set_property, + nullptr, nullptr, nullptr, input_finalize +}; + /* Each @input_class object must have a @form_class parent. */ static JSClass input_class = { "input", /* here, we unleash ourselves */ JSCLASS_HAS_PRIVATE, /* struct form_state *, or NULL if detached */ - JS_PropertyStub, nullptr, - input_get_property, input_set_property, - nullptr, nullptr, nullptr, input_finalize + &input_ops }; /* Tinyids of properties. Use negative values to distinguish these @@ -264,7 +272,7 @@ input_set_property_accessKey(JSContext *ctx, unsigned int argc, JS::Value *vp) } } if (accesskey == UCS_NO_CHAR) { - JS_ReportError(ctx, "Invalid UTF-16 sequence"); + JS_ReportErrorUTF8(ctx, "Invalid UTF-16 sequence"); return false; } @@ -1890,7 +1898,7 @@ spidermonkey_detach_form_state(struct form_state *fs) JSObject *jsinput = fs->ecmascript_obj; if (jsinput) { - JS::RootedObject r_jsinput(spidermonkey_empty_context, jsinput); +// JS::RootedObject r_jsinput(spidermonkey_empty_context, jsinput); /* This assumes JS_GetInstancePrivate and JS_SetPrivate * cannot GC. */ @@ -1898,12 +1906,12 @@ spidermonkey_detach_form_state(struct form_state *fs) * the private pointer of jsinput should be reset; * crashes seem possible either way. Resetting it is * easiest. */ - assert(JS_GetInstancePrivate(spidermonkey_empty_context, - r_jsinput, - &input_class, NULL) - == fs); - if_assert_failed {} - +// assert(JS_GetInstancePrivate(spidermonkey_empty_context, +// r_jsinput, +// &input_class, NULL) +// == fs); +// if_assert_failed {} +// JS_SetPrivate(jsinput, NULL); fs->ecmascript_obj = NULL; } @@ -1957,13 +1965,17 @@ get_form_control_object(JSContext *ctx, static struct form_view *form_get_form_view(JSContext *ctx, JSObject *jsform, JS::Value *argv); static bool form_elements_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); +static JSClassOps form_elements_ops = { + JS_PropertyStub, nullptr, + form_elements_get_property, JS_StrictPropertyStub, + nullptr, nullptr, nullptr, nullptr +}; + /* Each @form_elements_class object must have a @form_class parent. */ static JSClass form_elements_class = { "elements", JSCLASS_HAS_PRIVATE, - JS_PropertyStub, nullptr, - form_elements_get_property, JS_StrictPropertyStub, - nullptr, nullptr, nullptr, nullptr + &form_elements_ops }; static bool form_elements_item2(JSContext *ctx, JS::HandleObject hobj, int index, JS::MutableHandleValue hvp); @@ -3113,7 +3125,7 @@ spidermonkey_detach_form_view(struct form_view *fv) JSObject *jsform = fv->ecmascript_obj; if (jsform) { - JS::RootedObject r_jsform(spidermonkey_empty_context, jsform); +// JS::RootedObject r_jsform(spidermonkey_empty_context, jsform); /* This assumes JS_GetInstancePrivate and JS_SetPrivate * cannot GC. */ @@ -3121,11 +3133,11 @@ spidermonkey_detach_form_view(struct form_view *fv) * the private pointer of jsform should be reset; * crashes seem possible either way. Resetting it is * easiest. */ - assert(JS_GetInstancePrivate(spidermonkey_empty_context, - r_jsform, - &form_class, NULL) - == fv); - if_assert_failed {} +// assert(JS_GetInstancePrivate(spidermonkey_empty_context, +// r_jsform, +// &form_class, NULL) +// == fv); +// if_assert_failed {} JS_SetPrivate(jsform, NULL); fv->ecmascript_obj = NULL; @@ -3136,13 +3148,17 @@ spidermonkey_detach_form_view(struct form_view *fv) static bool forms_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); static bool forms_get_property_length(JSContext *ctx, unsigned int argc, JS::Value *vp); +JSClassOps forms_ops = { + JS_PropertyStub, nullptr, + forms_get_property, JS_StrictPropertyStub, + nullptr, nullptr, nullptr, nullptr +}; + /* Each @forms_class object must have a @document_class parent. */ JSClass forms_class = { "forms", JSCLASS_HAS_PRIVATE, - JS_PropertyStub, nullptr, - forms_get_property, JS_StrictPropertyStub, - nullptr, nullptr, nullptr, nullptr + &forms_ops }; static bool forms_item(JSContext *ctx, unsigned int argc, JS::Value *rval); @@ -3415,6 +3431,6 @@ jsval_to_accesskey(JSContext *ctx, JS::MutableHandleValue hvp) return join_utf16_surrogates(chr[0], chr[1]); } } - JS_ReportError(ctx, "Invalid UTF-16 sequence"); + JS_ReportErrorUTF8(ctx, "Invalid UTF-16 sequence"); return UCS_NO_CHAR; /* which the caller will reject */ } diff --git a/src/ecmascript/spidermonkey/heartbeat.c b/src/ecmascript/spidermonkey/heartbeat.c index e66d0f496..65383bf54 100644 --- a/src/ecmascript/spidermonkey/heartbeat.c +++ b/src/ecmascript/spidermonkey/heartbeat.c @@ -36,6 +36,11 @@ static struct itimerval heartbeat_timer = { { 1, 0 }, { 1, 0 } }; bool heartbeat_callback(JSContext *ctx) { + struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx); + + if (!interpreter->heartbeat || interpreter->heartbeat->ttl > 0) { + return true; + } return false; } @@ -63,7 +68,7 @@ check_heartbeats(void *data) ecmascript_timeout_dialog(term, max_exec_time); } - JS_RequestInterruptCallback(JS_GetRuntime(hb->interpreter->backend_data)); + JS_RequestInterruptCallback(hb->interpreter->backend_data); } } install_signal_handler(SIGVTALRM, check_heartbeats, NULL, 1); diff --git a/src/ecmascript/spidermonkey/location.c b/src/ecmascript/spidermonkey/location.c index 2059f4b6f..48827afaf 100644 --- a/src/ecmascript/spidermonkey/location.c +++ b/src/ecmascript/spidermonkey/location.c @@ -50,14 +50,18 @@ static bool history_back(JSContext *ctx, unsigned int argc, JS::Value *rval); static bool history_forward(JSContext *ctx, unsigned int argc, JS::Value *rval); static bool history_go(JSContext *ctx, unsigned int argc, JS::Value *rval); -JSClass history_class = { - "history", - JSCLASS_HAS_PRIVATE, +JSClassOps history_ops = { JS_PropertyStub, nullptr, JS_PropertyStub, JS_StrictPropertyStub, nullptr, nullptr, nullptr, nullptr }; +JSClass history_class = { + "history", + JSCLASS_HAS_PRIVATE, + &history_ops +}; + const spidermonkeyFunctionSpec history_funcs[] = { { "back", history_back, 0 }, { "forward", history_forward, 0 }, @@ -134,13 +138,16 @@ history_go(JSContext *ctx, unsigned int argc, JS::Value *rval) static bool location_get_property_href(JSContext *ctx, unsigned int argc, JS::Value *vp); static bool location_set_property_href(JSContext *ctx, unsigned int argc, JS::Value *vp); +JSClassOps location_ops = { + JS_PropertyStub, nullptr, + JS_PropertyStub, JS_StrictPropertyStub, + nullptr, nullptr, nullptr, nullptr +}; /* Each @location_class object must have a @window_class parent. */ JSClass location_class = { "location", JSCLASS_HAS_PRIVATE, - JS_PropertyStub, nullptr, - JS_PropertyStub, JS_StrictPropertyStub, - nullptr, nullptr, nullptr, nullptr + &location_ops }; /* Tinyids of properties. Use negative values to distinguish these diff --git a/src/ecmascript/spidermonkey/navigator.c b/src/ecmascript/spidermonkey/navigator.c index 3bbfdf79f..46c35dc1b 100644 --- a/src/ecmascript/spidermonkey/navigator.c +++ b/src/ecmascript/spidermonkey/navigator.c @@ -51,14 +51,18 @@ static bool navigator_get_property_language(JSContext *ctx, unsigned int argc, J static bool navigator_get_property_platform(JSContext *ctx, unsigned int argc, JS::Value *vp); static bool navigator_get_property_userAgent(JSContext *ctx, unsigned int argc, JS::Value *vp); -JSClass navigator_class = { - "navigator", - JSCLASS_HAS_PRIVATE, +JSClassOps navigator_ops = { JS_PropertyStub, nullptr, JS_PropertyStub, JS_StrictPropertyStub, nullptr, nullptr, nullptr, nullptr }; +JSClass navigator_class = { + "navigator", + JSCLASS_HAS_PRIVATE, + &navigator_ops +}; + /* Tinyids of properties. Use negative values to distinguish these * from array indexes (even though this object has no array elements). * ECMAScript code should not use these directly as in navigator[-1]; diff --git a/src/ecmascript/spidermonkey/unibar.c b/src/ecmascript/spidermonkey/unibar.c index 4a20598c6..1cf8aec5c 100644 --- a/src/ecmascript/spidermonkey/unibar.c +++ b/src/ecmascript/spidermonkey/unibar.c @@ -48,10 +48,20 @@ static bool unibar_get_property_visible(JSContext *ctx, unsigned int argc, JS::Value *vp); static bool unibar_set_property_visible(JSContext *ctx, unsigned int argc, JS::Value *vp); +JSClassOps menubar_ops = { + JS_PropertyStub, nullptr, + JS_PropertyStub, JS_StrictPropertyStub, + nullptr, nullptr, nullptr, nullptr +}; + /* Each @menubar_class object must have a @window_class parent. */ JSClass menubar_class = { "menubar", JSCLASS_HAS_PRIVATE, /* const char * "t" */ + &menubar_ops +}; + +JSClassOps statusbar_ops = { JS_PropertyStub, nullptr, JS_PropertyStub, JS_StrictPropertyStub, nullptr, nullptr, nullptr, nullptr @@ -60,9 +70,7 @@ JSClass menubar_class = { JSClass statusbar_class = { "statusbar", JSCLASS_HAS_PRIVATE, /* const char * "s" */ - JS_PropertyStub, nullptr, - JS_PropertyStub, JS_StrictPropertyStub, - nullptr, nullptr, nullptr, nullptr + &statusbar_ops }; /* Tinyids of properties. Use negative values to distinguish these diff --git a/src/ecmascript/spidermonkey/window.c b/src/ecmascript/spidermonkey/window.c index bd4f9d630..1279e2316 100644 --- a/src/ecmascript/spidermonkey/window.c +++ b/src/ecmascript/spidermonkey/window.c @@ -53,14 +53,18 @@ static bool window_get_property_status(JSContext *ctx, unsigned int argc, JS::Va static bool window_set_property_status(JSContext *ctx, unsigned int argc, JS::Value *vp); static bool window_get_property_top(JSContext *ctx, unsigned int argc, JS::Value *vp); -JSClass window_class = { - "window", - JSCLASS_HAS_PRIVATE | JSCLASS_GLOBAL_FLAGS, /* struct view_state * */ +JSClassOps window_ops = { JS_PropertyStub, nullptr, window_get_property, JS_StrictPropertyStub, nullptr, nullptr, nullptr, nullptr }; +JSClass window_class = { + "window", + JSCLASS_HAS_PRIVATE | JSCLASS_GLOBAL_FLAGS, /* struct view_state * */ + &window_ops +}; + /* Tinyids of properties. Use negative values to distinguish these * from array indexes (even though this object has no array elements). @@ -440,6 +444,7 @@ window_setTimeout(JSContext *ctx, unsigned int argc, JS::Value *rval) if (!code) return true; timeout = args[1].toInt32(); + if (timeout <= 0) { mem_free(code); return true; diff --git a/src/main/module.c b/src/main/module.c index 3d0ebb865..64aba901e 100644 --- a/src/main/module.c +++ b/src/main/module.c @@ -60,7 +60,7 @@ struct module *builtin_modules[] = { #ifdef CONFIG_COOKIES &cookies_module, #endif -#ifdef CONFIG_ECMASCRIPT +#ifdef CONFIG_ECMASCRIPT_SMJS &ecmascript_module, #endif #ifdef CONFIG_FORMHIST diff --git a/src/protocol/protocol.c b/src/protocol/protocol.c index aecfd098a..117311a20 100644 --- a/src/protocol/protocol.c +++ b/src/protocol/protocol.c @@ -219,7 +219,7 @@ generic_external_protocol_handler(struct session *ses, struct uri *uri) switch (uri->protocol) { case PROTOCOL_JAVASCRIPT: -#ifdef CONFIG_ECMASCRIPT +#ifdef CONFIG_ECMASCRIPT_SMJS ecmascript_protocol_handler(ses, uri); return; #else diff --git a/src/scripting/smjs/action_object.c b/src/scripting/smjs/action_object.c index 18c6aeb7b..532d9fab8 100644 --- a/src/scripting/smjs/action_object.c +++ b/src/scripting/smjs/action_object.c @@ -26,9 +26,7 @@ struct smjs_action_fn_callback_hop { static void smjs_action_fn_finalize(JSFreeOp *op, JSObject *obj); static bool smjs_action_fn_callback(JSContext *ctx, unsigned int argc, JS::Value *rval); -static const JSClass action_fn_class = { - "action_fn", - JSCLASS_HAS_PRIVATE, /* struct smjs_action_fn_callback_hop * */ +static JSClassOps action_fn_ops = { JS_PropertyStub, nullptr, JS_PropertyStub, JS_StrictPropertyStub, nullptr, nullptr, nullptr, @@ -37,6 +35,12 @@ static const JSClass action_fn_class = { smjs_action_fn_callback, }; +static const JSClass action_fn_class = { + "action_fn", + JSCLASS_HAS_PRIVATE, /* struct smjs_action_fn_callback_hop * */ + &action_fn_ops +}; + /* @action_fn_class.finalize */ static void smjs_action_fn_finalize(JSFreeOp *op, JSObject *obj) @@ -104,7 +108,7 @@ smjs_action_fn_callback(JSContext *ctx, unsigned int argc, JS::Value *rval) * * The "%s" prevents interpretation of any percent * signs in translations. */ - JS_ReportError(ctx, "%s", + JS_ReportErrorUTF8(ctx, "%s", _("Cannot run actions in a tab that doesn't " "have the focus", hop->ses->tab->term)); return false; /* make JS propagate the exception */ @@ -183,14 +187,18 @@ action_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS: return true; } -static const JSClass action_class = { - "action", - 0, +static JSClassOps action_ops = { JS_PropertyStub, nullptr, action_get_property, JS_StrictPropertyStub, nullptr, nullptr, nullptr, nullptr, }; +static const JSClass action_class = { + "action", + 0, + &action_ops +}; + static JSObject * smjs_get_action_object(void) { diff --git a/src/scripting/smjs/bookmarks.c b/src/scripting/smjs/bookmarks.c index fcedbaba8..d32bf1c4c 100644 --- a/src/scripting/smjs/bookmarks.c +++ b/src/scripting/smjs/bookmarks.c @@ -20,20 +20,28 @@ static void bookmark_finalize(JSFreeOp *op, JSObject *obj); static bool bookmark_folder_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); +static JSClassOps bookmark_ops = { + JS_PropertyStub, nullptr, + JS_PropertyStub, JS_StrictPropertyStub, + nullptr, nullptr, nullptr, bookmark_finalize, +}; + static const JSClass bookmark_class = { "bookmark", JSCLASS_HAS_PRIVATE, /* struct bookmark * */ + &bookmark_ops +}; + +static JSClassOps bookmark_folder_ops = { JS_PropertyStub, nullptr, - JS_PropertyStub, JS_StrictPropertyStub, + bookmark_folder_get_property, JS_StrictPropertyStub, nullptr, nullptr, nullptr, bookmark_finalize, }; static const JSClass bookmark_folder_class = { "bookmark_folder", JSCLASS_HAS_PRIVATE, /* struct bookmark * */ - JS_PropertyStub, nullptr, - bookmark_folder_get_property, JS_StrictPropertyStub, - nullptr, nullptr, nullptr, bookmark_finalize, + &bookmark_folder_ops }; static JSObject * diff --git a/src/scripting/smjs/cache_object.c b/src/scripting/smjs/cache_object.c index bd6204d21..0ea15d1c8 100644 --- a/src/scripting/smjs/cache_object.c +++ b/src/scripting/smjs/cache_object.c @@ -17,14 +17,18 @@ static void cache_entry_finalize(JSFreeOp *op, JSObject *obj); -static const JSClass cache_entry_class = { - "cache_entry", - JSCLASS_HAS_PRIVATE, /* struct cache_entry *; a weak reference */ +static JSClassOps cache_entry_ops = { JS_PropertyStub, nullptr, JS_PropertyStub, JS_StrictPropertyStub, nullptr, nullptr, nullptr, cache_entry_finalize }; +static const JSClass cache_entry_class = { + "cache_entry", + JSCLASS_HAS_PRIVATE, /* struct cache_entry *; a weak reference */ + &cache_entry_ops +}; + /* Tinyids of properties. Use negative values to distinguish these * from array indexes (even though this object has no array elements). * ECMAScript code should not use these directly as in cache_entry[-1]; diff --git a/src/scripting/smjs/core.c b/src/scripting/smjs/core.c index 94285c326..cca5caecf 100644 --- a/src/scripting/smjs/core.c +++ b/src/scripting/smjs/core.c @@ -37,8 +37,88 @@ alert_smjs_error(unsigned char *msg) smjs_ses, msg); } +static bool +PrintError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult, + JSErrorReport* report, bool reportWarnings) +{ + MOZ_ASSERT(report); + + /* Conditionally ignore reported warnings. */ + if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings) + return false; + + char* prefix = nullptr; + if (report->filename) + prefix = JS_smprintf("%s:", report->filename); + if (report->lineno) { + char* tmp = prefix; + prefix = JS_smprintf("%s%u:%u ", tmp ? tmp : "", report->lineno, report->column); + JS_free(cx, tmp); + } + if (JSREPORT_IS_WARNING(report->flags)) { + char* tmp = prefix; + prefix = JS_smprintf("%s%swarning: ", + tmp ? tmp : "", + JSREPORT_IS_STRICT(report->flags) ? "strict " : ""); + JS_free(cx, tmp); + } + + const char* message = toStringResult ? toStringResult.c_str() : report->message().c_str(); + + /* embedded newlines -- argh! */ + const char* ctmp; + while ((ctmp = strchr(message, '\n')) != 0) { + ctmp++; + if (prefix) + fputs(prefix, file); + fwrite(message, 1, ctmp - message, file); + message = ctmp; + } + + /* If there were no filename or lineno, the prefix might be empty */ + if (prefix) + fputs(prefix, file); + fputs(message, file); + + if (const char16_t* linebuf = report->linebuf()) { + size_t n = report->linebufLength(); + + fputs(":\n", file); + if (prefix) + fputs(prefix, file); + + for (size_t i = 0; i < n; i++) + fputc(static_cast(linebuf[i]), file); + + // linebuf usually ends with a newline. If not, add one here. + if (n == 0 || linebuf[n-1] != '\n') + fputc('\n', file); + + if (prefix) + fputs(prefix, file); + + n = report->tokenOffset(); + for (size_t i = 0, j = 0; i < n; i++) { + if (linebuf[i] == '\t') { + for (size_t k = (j + 8) & ~7; j < k; j++) + fputc('.', file); + continue; + } + fputc('.', file); + j++; + } + fputc('^', file); + } + fputc('\n', file); + fflush(file); + JS_free(cx, prefix); + return true; +} + + + static void -error_reporter(JSContext *ctx, const char *message, JSErrorReport *report) +error_reporter(JSContext *ctx, JSErrorReport *report) { unsigned char *strict, *exception, *warning, *error; struct string msg; @@ -51,11 +131,12 @@ error_reporter(JSContext *ctx, const char *message, JSErrorReport *report) warning = JSREPORT_IS_WARNING(report->flags) ? " warning" : ""; error = !report->flags ? " error" : ""; + PrintError(ctx, stderr, JS::ConstUTF8CharsZ(), report, true/*reportWarnings*/); + add_format_to_string(&msg, "A client script raised the following%s%s%s%s", strict, exception, warning, error); add_to_string(&msg, ":\n\n"); - add_to_string(&msg, message); add_format_to_string(&msg, "\n\n%d:%d ", report->lineno, report->column); @@ -153,13 +234,13 @@ init_smjs(struct module *module) { if (!spidermonkey_runtime_addref()) return; - smjs_ctx = JS_NewContext(spidermonkey_runtime, 8192); + smjs_ctx = JS_NewContext(8L * 1024 * 1024); if (!smjs_ctx) { spidermonkey_runtime_release(); return; } - JS_SetErrorReporter(spidermonkey_runtime, error_reporter); + JS::SetWarningReporter(smjs_ctx, error_reporter); smjs_init_global_object(); diff --git a/src/scripting/smjs/elinks_object.c b/src/scripting/smjs/elinks_object.c index 9a84ca18d..50b709d6c 100644 --- a/src/scripting/smjs/elinks_object.c +++ b/src/scripting/smjs/elinks_object.c @@ -108,14 +108,18 @@ static const JSPropertySpec elinks_props[] = { static bool elinks_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); static bool elinks_set_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); -static const JSClass elinks_class = { - "elinks", - 0, +static const JSClassOps elinks_ops = { JS_PropertyStub, nullptr, elinks_get_property, elinks_set_property, nullptr, nullptr, nullptr, nullptr }; +static const JSClass elinks_class = { + "elinks", + 0, + &elinks_ops +}; + /* @elinks_class.getProperty */ static bool @@ -263,15 +267,12 @@ smjs_invoke_elinks_object_method(unsigned char *method, int argc, JS::Value *arg assert(argv); JS::RootedObject r_smjs_elinks_object(smjs_ctx, smjs_elinks_object); - JS::Value val; - JS::RootedValue fun(smjs_ctx, val); + JS::RootedValue fun(smjs_ctx); if (false == JS_GetProperty(smjs_ctx, r_smjs_elinks_object, - method, &fun)) - return false; - - if (rval.isUndefined()) + method, &fun)) { return false; + } return JS_CallFunctionValue(smjs_ctx, r_smjs_elinks_object, fun, args, rval); } diff --git a/src/scripting/smjs/global_object.c b/src/scripting/smjs/global_object.c index 32491b777..733d8527c 100644 --- a/src/scripting/smjs/global_object.c +++ b/src/scripting/smjs/global_object.c @@ -15,14 +15,17 @@ using namespace JS; JSObject *smjs_global_object; - -static const JSClass global_class = { - "global", JSCLASS_GLOBAL_FLAGS, +static const JSClassOps global_ops = { JS_PropertyStub, nullptr, JS_PropertyStub, JS_StrictPropertyStub, nullptr, nullptr, nullptr, nullptr }; +static const JSClass global_class = { + "global", JSCLASS_GLOBAL_FLAGS, + &global_ops +}; + static JSObject * smjs_get_global_object(void) { @@ -30,9 +33,13 @@ smjs_get_global_object(void) JSAutoCompartment *acc = NULL; JSAutoRequest ar(smjs_ctx); - RootedObject jsobj(smjs_ctx); + JS::CompartmentOptions opts; - jsobj = JS_NewGlobalObject(smjs_ctx, (JSClass *) &global_class, NULL, JS::DontFireOnNewGlobalHook); + if (!JS::InitSelfHostedCode(smjs_ctx)) { + return NULL; + } + + JS::RootedObject jsobj(smjs_ctx, JS_NewGlobalObject(smjs_ctx, (JSClass *) &global_class, NULL, JS::DontFireOnNewGlobalHook, opts)); if (!jsobj) return NULL; diff --git a/src/scripting/smjs/globhist.c b/src/scripting/smjs/globhist.c index 52f618ac0..28ecf8b3f 100644 --- a/src/scripting/smjs/globhist.c +++ b/src/scripting/smjs/globhist.c @@ -17,15 +17,19 @@ static bool smjs_globhist_item_set_property(JSContext *ctx, JS::HandleObject hob static void smjs_globhist_item_finalize(JSFreeOp *op, JSObject *obj); -static const JSClass smjs_globhist_item_class = { - "global_history_item", - JSCLASS_HAS_PRIVATE, /* struct global_history_item * */ +static const JSClassOps smjs_globhist_item_ops = { JS_PropertyStub, nullptr, smjs_globhist_item_get_property, smjs_globhist_item_set_property, nullptr, nullptr, nullptr, smjs_globhist_item_finalize, }; +static const JSClass smjs_globhist_item_class = { + "global_history_item", + JSCLASS_HAS_PRIVATE, /* struct global_history_item * */ + &smjs_globhist_item_ops +}; + /* @smjs_globhist_item_class.finalize */ static void smjs_globhist_item_finalize(JSFreeOp *op, JSObject *obj) @@ -243,13 +247,17 @@ ret_null: return true; } -static const JSClass smjs_globhist_class = { - "global_history", 0, +static const JSClassOps smjs_globhist_ops = { JS_PropertyStub, nullptr, smjs_globhist_get_property, JS_StrictPropertyStub, nullptr, nullptr, nullptr, nullptr }; +static const JSClass smjs_globhist_class = { + "global_history", 0, + &smjs_globhist_ops +}; + static JSObject * smjs_get_globhist_object(void) { diff --git a/src/scripting/smjs/hooks.c b/src/scripting/smjs/hooks.c index 0359927a2..a52330125 100644 --- a/src/scripting/smjs/hooks.c +++ b/src/scripting/smjs/hooks.c @@ -27,8 +27,8 @@ script_hook_url(va_list ap, void *data) unsigned char **url = va_arg(ap, unsigned char **); struct session *ses = va_arg(ap, struct session *); enum evhook_status ret = EVENT_HOOK_STATUS_NEXT; - JS::Value args[3], rval; - JS::RootedValue r_rval(smjs_ctx, rval); + JS::Value args[3]; + JS::RootedValue r_rval(smjs_ctx); if (*url == NULL) return EVENT_HOOK_STATUS_NEXT; @@ -59,12 +59,14 @@ script_hook_pre_format_html(va_list ap, void *data) 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 = NULL; - JS::Value args[4], rval; - JS::RootedValue r_rval(smjs_ctx, rval); + JS::Value args[4]; + JS::RootedValue r_rval(smjs_ctx); evhook_use_params(ses && cached); - if (!smjs_ctx || !cached->length) goto end; + if (!smjs_ctx || !cached->length) { + goto end; + } smjs_ses = ses; @@ -81,9 +83,10 @@ script_hook_pre_format_html(va_list ap, void *data) args[3].setObject(*view_state_object); if (true == smjs_invoke_elinks_object_method("preformat_html", - 2, args, &r_rval)) + 2, args, &r_rval)) { if (false == r_rval.toBoolean()) ret = EVENT_HOOK_STATUS_LAST; + } end: smjs_ses = NULL; diff --git a/src/scripting/smjs/keybinding.c b/src/scripting/smjs/keybinding.c index 460d72b3e..5c81c4672 100644 --- a/src/scripting/smjs/keybinding.c +++ b/src/scripting/smjs/keybinding.c @@ -17,14 +17,18 @@ static bool keymap_get_property(JSContext *ctx, JS::HandleObject hobj, JS::Handl static bool keymap_set_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); static void keymap_finalize(JSFreeOp *op, JSObject *obj); -static const JSClass keymap_class = { - "keymap", - JSCLASS_HAS_PRIVATE, /* int * */ +static const JSClassOps keymap_ops = { JS_PropertyStub, nullptr, keymap_get_property, keymap_set_property, nullptr, nullptr, nullptr, keymap_finalize, }; +static const JSClass keymap_class = { + "keymap", + JSCLASS_HAS_PRIVATE, /* int * */ + &keymap_ops +}; + /* @keymap_class.getProperty */ static bool keymap_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp) @@ -220,14 +224,18 @@ smjs_get_keymap_object(enum keymap_id keymap_id) return keymap_object; } -static const JSClass keymaps_hash_class = { - "keymaps_hash", - JSCLASS_HAS_PRIVATE, +static const JSClassOps keymap_hash_ops = { JS_PropertyStub, nullptr, JS_PropertyStub, JS_StrictPropertyStub, nullptr, nullptr, nullptr, nullptr, }; +static const JSClass keymaps_hash_class = { + "keymaps_hash", + JSCLASS_HAS_PRIVATE, + &keymap_hash_ops +}; + static JSObject * smjs_get_keymap_hash_object(void) { diff --git a/src/scripting/smjs/session_object.c b/src/scripting/smjs/session_object.c index 8366e317f..f91e65879 100644 --- a/src/scripting/smjs/session_object.c +++ b/src/scripting/smjs/session_object.c @@ -35,24 +35,32 @@ static bool session_set_property(JSContext *ctx, JS::HandleObject hobj, JS::Hand static void session_finalize(JSFreeOp *op, JSObject *obj); static bool session_construct(JSContext *ctx, unsigned int argc, JS::Value *rval); -static const JSClass session_class = { - "session", - JSCLASS_HAS_PRIVATE, /* struct session *; a weak reference */ +static const JSClassOps session_ops = { JS_PropertyStub, nullptr, session_get_property, session_set_property, nullptr, nullptr, nullptr, session_finalize, NULL, NULL, NULL, session_construct }; +static const JSClass session_class = { + "session", + JSCLASS_HAS_PRIVATE, /* struct session *; a weak reference */ + &session_ops +}; + static bool smjs_location_array_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); static void smjs_location_array_finalize(JSFreeOp *op, JSObject *obj); +static const JSClassOps location_array_ops = { + JS_PropertyStub, nullptr, + smjs_location_array_get_property, JS_StrictPropertyStub, + nullptr, nullptr, nullptr, smjs_location_array_finalize, +}; + static const JSClass location_array_class = { "location_array", JSCLASS_HAS_PRIVATE, /* struct session *; a weak reference */ - JS_PropertyStub, nullptr, - smjs_location_array_get_property, JS_StrictPropertyStub, - nullptr, nullptr, nullptr, smjs_location_array_finalize, + &location_array_ops }; /* location_array_class is the class for array object, the elements of which @@ -1076,14 +1084,18 @@ session_array_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId h return true; } -static const JSClass session_array_class = { - "session_array", - JSCLASS_HAS_PRIVATE, /* struct terminal *term; a weak reference */ +static const JSClassOps session_array_ops = { JS_PropertyStub, nullptr, session_array_get_property, JS_StrictPropertyStub, nullptr, nullptr, nullptr, nullptr }; +static const JSClass session_array_class = { + "session_array", + JSCLASS_HAS_PRIVATE, /* struct terminal *term; a weak reference */ + &session_array_ops +}; + JSObject * smjs_get_session_array_object(struct terminal *term) { diff --git a/src/scripting/smjs/terminal_object.c b/src/scripting/smjs/terminal_object.c index 49506f650..b286a842b 100644 --- a/src/scripting/smjs/terminal_object.c +++ b/src/scripting/smjs/terminal_object.c @@ -20,14 +20,18 @@ static bool terminal_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); static void terminal_finalize(JSFreeOp *op, JSObject *obj); -static const JSClass terminal_class = { - "terminal", - JSCLASS_HAS_PRIVATE, /* struct terminal *; a weak refernce */ +static const JSClassOps terminal_ops = { JS_PropertyStub, nullptr, terminal_get_property, JS_StrictPropertyStub, nullptr, nullptr, nullptr, terminal_finalize }; +static const JSClass terminal_class = { + "terminal", + JSCLASS_HAS_PRIVATE, /* struct terminal *; a weak refernce */ + &terminal_ops +}; + enum terminal_prop { TERMINAL_TAB, }; @@ -187,14 +191,18 @@ terminal_array_get_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId ; } -static const JSClass terminal_array_class = { - "terminal_array", - 0, +static const JSClassOps terminal_array_ops = { JS_PropertyStub, nullptr, terminal_array_get_property, JS_StrictPropertyStub, nullptr, nullptr, nullptr, nullptr }; +static const JSClass terminal_array_class = { + "terminal_array", + 0, + &terminal_array_ops +}; + /** Return an SMJS object that scripts can use an array to get terminal * objects. */ static JSObject * diff --git a/src/scripting/smjs/view_state_object.c b/src/scripting/smjs/view_state_object.c index be3ffca9c..101c27053 100644 --- a/src/scripting/smjs/view_state_object.c +++ b/src/scripting/smjs/view_state_object.c @@ -24,14 +24,18 @@ static bool view_state_get_property(JSContext *ctx, JS::HandleObject hobj, JS::H static bool view_state_set_property(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp); static void view_state_finalize(JSFreeOp *op, JSObject *obj); -static const JSClass view_state_class = { - "view_state", - JSCLASS_HAS_PRIVATE, /* struct view_state * */ +static const JSClassOps view_state_ops = { JS_PropertyStub, nullptr, view_state_get_property, view_state_set_property, nullptr, nullptr, nullptr, view_state_finalize }; +static const JSClass view_state_class = { + "view_state", + JSCLASS_HAS_PRIVATE, /* struct view_state * */ + &view_state_ops +}; + /* Tinyids of properties. Use negative values to distinguish these * from array indexes (even though this object has no array elements). * ECMAScript code should not use these directly as in view_state[-1]; @@ -255,22 +259,22 @@ smjs_get_view_state_object(struct view_state *vs) } static bool -smjs_elinks_get_view_state(JSContext *ctx, JS::HandleObject hobj, JS::HandleId hid, JS::MutableHandleValue hvp) +smjs_elinks_get_view_state(JSContext *ctx, unsigned int argc, JS::Value *vp) { - JSObject *vs_obj; - struct view_state *vs; + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); - hvp.setNull(); + args.rval().setNull(); if (!smjs_ses || !have_location(smjs_ses)) return true; - vs = &cur_loc(smjs_ses)->vs; + struct view_state *vs = &cur_loc(smjs_ses)->vs; if (!vs) return true; - vs_obj = smjs_get_view_state_object(vs); + JSObject *vs_obj = smjs_get_view_state_object(vs); if (!vs_obj) return true; - hvp.setObject(*vs_obj); + args.rval().setObject(*vs_obj); return true; } @@ -308,6 +312,6 @@ smjs_init_view_state_interface(void) JS::RootedObject r_smjs_elinks_object(smjs_ctx, smjs_elinks_object); JS_DefineProperty(smjs_ctx, r_smjs_elinks_object, "vs", (int32_t)0, - (unsigned int)(JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY), smjs_elinks_get_view_state, JS_StrictPropertyStub + (unsigned int)(JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY), smjs_elinks_get_view_state, nullptr/*JS_StrictPropertyStub*/ ); } diff --git a/src/viewer/text/form.c b/src/viewer/text/form.c index e55725fe0..8e77a321c 100644 --- a/src/viewer/text/form.c +++ b/src/viewer/text/form.c @@ -252,7 +252,7 @@ find_form_state(struct document_view *doc_view, struct el_form_control *fc) if (n >= vs->form_info_len) { int nn = n + 1; -#ifdef CONFIG_ECMASCRIPT +#ifdef CONFIG_ECMASCRIPT_SMJS const struct form_state *const old_form_info = vs->form_info; #endif @@ -261,7 +261,7 @@ find_form_state(struct document_view *doc_view, struct el_form_control *fc) vs->form_info = fs; vs->form_info_len = nn; -#ifdef CONFIG_ECMASCRIPT +#ifdef CONFIG_ECMASCRIPT_SMJS /* TODO: Standard C does not allow this comparison; * if the memory to which old_form_info pointed has * been freed, then the value of the pointer itself is @@ -275,7 +275,7 @@ find_form_state(struct document_view *doc_view, struct el_form_control *fc) for (nn = 0; nn < vs->form_info_len; nn++) ecmascript_moved_form_state(&vs->form_info[nn]); } -#endif /* CONFIG_ECMASCRIPT */ +#endif /* CONFIG_ECMASCRIPT_SMJS */ } fs = &vs->form_info[n]; @@ -353,7 +353,7 @@ find_form_by_form_view(struct document *document, struct form_view *fv) void done_form_state(struct form_state *fs) { -#ifdef CONFIG_ECMASCRIPT +#ifdef CONFIG_ECMASCRIPT_SMJS ecmascript_detach_form_state(fs); #endif mem_free_if(fs->value); @@ -365,7 +365,7 @@ done_form_state(struct form_state *fs) void done_form_view(struct form_view *fv) { -#ifdef CONFIG_ECMASCRIPT +#ifdef CONFIG_ECMASCRIPT_SMJS ecmascript_detach_form_view(fv); #endif mem_free(fv); diff --git a/src/viewer/text/link.c b/src/viewer/text/link.c index 1b3354eed..e7af384fd 100644 --- a/src/viewer/text/link.c +++ b/src/viewer/text/link.c @@ -52,7 +52,7 @@ static int current_link_evhook(struct document_view *doc_view, enum script_event_hook_type type) { -#ifdef CONFIG_ECMASCRIPT +#ifdef CONFIG_ECMASCRIPT_SMJS struct link *link; struct script_event_hook *evhook; @@ -915,7 +915,7 @@ call_onsubmit_and_submit(struct session *ses, struct document_view *doc_view, assert(fc->form); /* regardless of whether there is a FORM element */ if_assert_failed return 0; -#ifdef CONFIG_ECMASCRIPT +#ifdef CONFIG_ECMASCRIPT_SMJS /* If the form has multiple submit buttons, this does not * explicitly tell the ECMAScript code which of them was * pressed. W3C DOM Level 3 doesn't seem to include such a @@ -952,7 +952,7 @@ call_onsubmit_and_submit(struct session *ses, struct document_view *doc_view, if (!res) return 1; } } -#endif /* CONFIG_ECMASCRIPT */ +#endif /* CONFIG_ECMASCRIPT_SMJS */ uri = get_form_uri(ses, doc_view, fc); if (!uri) return 0; diff --git a/src/viewer/text/vs.c b/src/viewer/text/vs.c index 7462cb512..fc5f9717e 100644 --- a/src/viewer/text/vs.c +++ b/src/viewer/text/vs.c @@ -38,7 +38,7 @@ init_vs(struct view_state *vs, struct uri *uri, int plain) vs->plain = plain; vs->uri = uri ? get_uri_reference(uri) : NULL; vs->did_fragment = !uri->fragmentlen; -#ifdef CONFIG_ECMASCRIPT +#ifdef CONFIG_ECMASCRIPT_SMJS /* If we ever get to render this vs, give it an interpreter. */ vs->ecmascript_fragile = 1; #endif @@ -67,7 +67,7 @@ destroy_vs(struct view_state *vs, int blast_ecmascript) } if (vs->uri) done_uri(vs->uri); -#ifdef CONFIG_ECMASCRIPT +#ifdef CONFIG_ECMASCRIPT_SMJS if (blast_ecmascript && vs->ecmascript) ecmascript_put_interpreter(vs->ecmascript); #endif @@ -87,7 +87,7 @@ copy_vs(struct view_state *dst, struct view_state *src) /* We do not copy ecmascript stuff around since it's specific for * a single location, offsprings (followups and so) nedd their own. */ -#ifdef CONFIG_ECMASCRIPT +#ifdef CONFIG_ECMASCRIPT_SMJS dst->ecmascript = NULL; /* If we ever get to render this vs, give it an interpreter. */ dst->ecmascript_fragile = 1; @@ -131,7 +131,7 @@ copy_vs(struct view_state *dst, struct view_state *src) struct form_state *srcfs = &src->form_info[i]; struct form_state *dstfs = &dst->form_info[i]; -#ifdef CONFIG_ECMASCRIPT +#ifdef CONFIG_ECMASCRIPT_SMJS dstfs->ecmascript_obj = NULL; #endif if (srcfs->value) diff --git a/test/ecmascript/scroll.html b/test/ecmascript/scroll.html index 3ddb94783..81b2216c7 100644 --- a/test/ecmascript/scroll.html +++ b/test/ecmascript/scroll.html @@ -6,7 +6,7 @@ function scrollText() { tekst = tekst.substring(1, tekst.length) + znak; return tekst.substring(0, 80); } -function scroll () { +function scroll() { document.title = scrollText(); setTimeout("scroll()", 100); }