Commit 2c7f3bc6 authored by Rob Swindell's avatar Rob Swindell 💬
Browse files

Allow fine-grained control over JavaScript compiler options via *.ini

JavaScriptOptions bit-field can be set in sbbs.ini and jsexec.ini to over-ride the default JS compiler options which have been changed from 0 to (options previously only used by JSDoor):
JIT | METHODJIT | COMPILE_N_GO | PROFILING

* JIT - TraceMonkey
* METHODJIT - JägerMonkey
* COMPILE_N_GO - compile-time scope chain resolution of consts
* PROFILING - Choose between TraceMonkey and JägerMonkey at compile-time based on profiling results

Other options available but not enabled by default:
* STRICT - warn on debious practice (i.e. similar to "use strict")
* WERROR - convert warnings to errors
* VAROBJFIX -  use last object on scope chain as the ECMA 'variables object'
* RELIMIT - Throw exception on any regular expression which backtracks more than n^3 times, where n is length of the input string
* ANONFUNFIX - Disallow function () {} in statement context per ECMA-262 Edition 3.
* METHODJIT_ALWAYS - Always whole-method JIT, don't tune at run-time.

Also:
- Fixed JS warning string formatting (missing space separator).
- Removed an extraneous new-line in lprintf() call in mailsrvr.
- Added basic assertEq() global method to jsexec, required when running SpiderMonkey test scripts.
parent 427e1cb4
Pipeline #1425 failed with stage
in 9 minutes and 13 seconds
/* Synchronet JavaScript "global" object properties/methods for all servers */
/* $Id: js_global.c,v 1.409 2020/08/09 01:53:52 rswindell Exp $ */
// vi: tabstop=4
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
......@@ -16,21 +13,9 @@
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
*
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
......@@ -333,6 +318,7 @@ js_load(JSContext *cx, uintN argc, jsval *arglist)
JS_RESUMEREQUEST(cx, rc);
return(JS_FALSE);
}
JS_SetOptions(bg->cx, p->startup->options);
JS_BEGINREQUEST(bg->cx);
if(!js_CreateCommonObjects(bg->cx
......
......@@ -29,6 +29,7 @@
#include <termios.h>
#endif
#define STARTUP_INI_BITDESC_TABLES
#include "sbbs.h"
#include "ciolib.h"
#include "ini_file.h"
......@@ -45,6 +46,7 @@ static const char* strJavaScriptMaxBytes ="JavaScriptMaxBytes";
static const char* strJavaScriptTimeLimit ="JavaScriptTimeLimit";
static const char* strJavaScriptGcInterval ="JavaScriptGcInterval";
static const char* strJavaScriptYieldInterval ="JavaScriptYieldInterval";
static const char* strJavaScriptOptions ="JavaScriptOptions";
js_startup_t startup;
JSRuntime* js_runtime;
......@@ -54,6 +56,7 @@ js_callback_t cb;
scfg_t scfg;
char* text[TOTAL_TEXT];
ulong js_max_bytes=JAVASCRIPT_MAX_BYTES;
ulong js_opts = JAVASCRIPT_OPTIONS;
FILE* confp;
FILE* errfp;
FILE* nulfp;
......@@ -700,6 +703,28 @@ js_putenv(JSContext *cx, uintN argc, jsval *arglist)
return(JS_TRUE);
}
// Forked from mozilla/js/src/shell/js.cpp: AssertEq()
static JSBool
js_AssertEq(JSContext *cx, uintN argc, jsval *vp)
{
if (!(argc == 2 || (argc == 3 && JSVAL_IS_STRING(JS_ARGV(cx, vp)[2])))) {
JS_ReportError(cx, "assertEq: missing or invalid args");
return JS_FALSE;
}
jsval *argv = JS_ARGV(cx, vp);
JSBool same;
if (!JS_SameValue(cx, argv[0], argv[1], &same))
return JS_FALSE;
if (!same) {
JS_ReportError(cx, "not equal");
return JS_FALSE;
}
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
static jsSyncMethodSpec js_global_functions[] = {
{"log", js_log, 1},
{"read", js_read, 1},
......@@ -710,13 +735,14 @@ static jsSyncMethodSpec js_global_functions[] = {
{"write", js_write, 0},
{"writeln", js_writeln, 0},
{"print", js_writeln, 0},
{"printf", jse_printf, 1},
{"printf", jse_printf, 1},
{"alert", js_alert, 1},
{"prompt", js_prompt, 1},
{"confirm", js_confirm, 1},
{"deny", js_deny, 1},
{"chdir", js_chdir, 1},
{"putenv", js_putenv, 1},
{"assertEq", js_AssertEq, 2},
{0}
};
......@@ -817,9 +843,7 @@ static BOOL js_init(char** env)
if((js_cx = JS_NewContext(js_runtime, JAVASCRIPT_CONTEXT_STACK))==NULL)
return(FALSE);
#ifdef JSDOOR
JS_SetOptions(js_cx, JSOPTION_JIT | JSOPTION_METHODJIT | JSOPTION_COMPILE_N_GO | JSOPTION_PROFILING);
#endif
JS_SetOptions(js_cx, js_opts);
JS_BEGINREQUEST(js_cx);
JS_SetErrorReporter(js_cx, js_ErrorReporter);
......@@ -1138,6 +1162,7 @@ void get_ini_values(str_list_t ini, const char* section, js_callback_t* cb)
cb->gc_interval = iniGetInteger(ini, section, strJavaScriptGcInterval , cb->gc_interval);
cb->yield_interval = iniGetInteger(ini, section, strJavaScriptYieldInterval , cb->yield_interval);
cb->auto_terminate = iniGetBool(ini, section, "AutoTerminate" , cb->auto_terminate);
js_opts = iniGetBitField(ini, section, strJavaScriptOptions , js_options, js_opts);
}
/*********************/
......
......@@ -2257,7 +2257,7 @@ js_mailproc(SOCKET sock, client_t* client, user_t* user, struct mailproc* mailpr
*result = 0;
do {
if(*js_runtime==NULL) {
lprintf(LOG_DEBUG,"%04d %s JavaScript: Creating runtime: %lu bytes\n"
lprintf(LOG_DEBUG,"%04d %s JavaScript: Creating runtime: %lu bytes"
,sock, log_prefix, startup->js.max_bytes);
if((*js_runtime = jsrt_GetNew(startup->js.max_bytes, 1000, __FILE__, __LINE__))==NULL)
......@@ -2267,6 +2267,7 @@ js_mailproc(SOCKET sock, client_t* client, user_t* user, struct mailproc* mailpr
if(*js_cx==NULL) {
if((*js_cx = JS_NewContext(*js_runtime, JAVASCRIPT_CONTEXT_STACK))==NULL)
return FALSE;
JS_SetOptions(*js_cx, startup->js.options);
}
JS_BEGINREQUEST(*js_cx);
......
......@@ -1247,9 +1247,9 @@ js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
if(JSREPORT_IS_WARNING(report->flags)) {
if(JSREPORT_IS_STRICT(report->flags))
warning="strict warning";
warning="strict warning ";
else
warning="warning";
warning="warning ";
log_level = LOG_WARNING;
} else {
warning=nulstr;
......@@ -1276,6 +1276,7 @@ JSContext* sbbs_t::js_init(JSRuntime** runtime, JSObject** glob, const char* des
if((js_cx = JS_NewContext(*runtime, JAVASCRIPT_CONTEXT_STACK))==NULL)
return NULL;
JS_SetOptions(js_cx, startup->js.options);
JS_BEGINREQUEST(js_cx);
memset(&js_callback,0,sizeof(js_callback));
......
......@@ -58,6 +58,7 @@ static const char* strJavaScriptTimeLimit ="JavaScriptTimeLimit";
static const char* strJavaScriptGcInterval ="JavaScriptGcInterval";
static const char* strJavaScriptYieldInterval ="JavaScriptYieldInterval";
static const char* strJavaScriptLoadPath ="JavaScriptLoadPath";
static const char* strJavaScriptOptions ="JavaScriptOptions";
static const char* strSemFileCheckFrequency ="SemFileCheckFrequency";
#define DEFAULT_LOG_LEVEL LOG_DEBUG
......@@ -104,6 +105,7 @@ void sbbs_get_js_settings(
js->time_limit = iniGetInteger(list,section,strJavaScriptTimeLimit ,defaults->time_limit);
js->gc_interval = iniGetInteger(list,section,strJavaScriptGcInterval ,defaults->gc_interval);
js->yield_interval = iniGetInteger(list,section,strJavaScriptYieldInterval ,defaults->yield_interval);
js->options = iniGetBitField(list, section, strJavaScriptOptions ,js_options, defaults->options);
/* Get JavaScriptLoadPath, use default if key is missing, use blank if key value is blank */
if((p=iniGetExistingString(list, section, strJavaScriptLoadPath, nulstr, value)) == NULL) {
......@@ -128,6 +130,7 @@ BOOL sbbs_set_js_settings(
,JAVASCRIPT_TIME_LIMIT
,JAVASCRIPT_GC_INTERVAL
,JAVASCRIPT_YIELD_INTERVAL
,JAVASCRIPT_OPTIONS
,JAVASCRIPT_LOAD_PATH
};
SAFECOPY(global_defaults.load_path, JAVASCRIPT_LOAD_PATH);
......@@ -226,6 +229,7 @@ static void get_ini_globals(str_list_t list, global_startup_t* global)
global->js.time_limit = JAVASCRIPT_TIME_LIMIT;
global->js.gc_interval = JAVASCRIPT_GC_INTERVAL;
global->js.yield_interval = JAVASCRIPT_YIELD_INTERVAL;
global->js.options = JAVASCRIPT_OPTIONS;
SAFECOPY(global->js.load_path, JAVASCRIPT_LOAD_PATH);
/* Read .ini values here */
......
......@@ -66,6 +66,7 @@
#define JAVASCRIPT_GC_INTERVAL 100
#define JAVASCRIPT_LOAD_PATH "load"
#define JAVASCRIPT_LOAD_PATH_LIST "load_path_list"
#define JAVASCRIPT_OPTIONS 0xC810 // JSOPTION_JIT | JSOPTION_METHODJIT | JSOPTION_COMPILE_N_GO | JSOPTION_PROFILING
struct js_callback;
typedef struct js_callback {
......
......@@ -754,6 +754,7 @@ js_initcx(JSRuntime* js_runtime, SOCKET sock, service_client_t* service_client,
if((js_cx = JS_NewContext(js_runtime, JAVASCRIPT_CONTEXT_STACK))==NULL)
return(NULL);
JS_SetOptions(js_cx, startup->js.options);
JS_BEGINREQUEST(js_cx);
JS_SetErrorReporter(js_cx, js_ErrorReporter);
......
......@@ -38,6 +38,7 @@ typedef struct {
ulong time_limit; /* maximum number of ticks (for infinite loop detection) */
ulong gc_interval; /* number of ticks between garbage collection attempts */
ulong yield_interval; /* number of ticks between time-slice yields */
ulong options;
char load_path[INI_MAX_VALUE_LEN]; /* additional (comma-separated) directories to search for load()ed scripts */
} js_startup_t;
......@@ -211,6 +212,22 @@ static ini_bitdesc_t bbs_options[] = {
{ 0 ,NULL }
};
static ini_bitdesc_t js_options[] = {
{ 1<<0 ,"STRICT" },
{ 1<<1 ,"WERROR" },
{ 1<<2 ,"VAROBJFIX" },
{ 1<<4 ,"COMPILE_N_GO" },
{ 1<<9 ,"RELIMIT" },
{ 1<<10 ,"ANONFUNFIX" },
{ 1<<11 ,"JIT" },
{ 1<<14 ,"METHODJIT" },
{ 1<<15 ,"PROFILING" },
{ 1<<16 ,"METHODJIT_ALWAYS" },
/* terminator */
{ 0 ,NULL }
};
#endif
#ifdef __cplusplus
......
......@@ -5754,9 +5754,11 @@ js_initcx(http_session_t *session)
if((js_cx = JS_NewContext(session->js_runtime, JAVASCRIPT_CONTEXT_STACK))==NULL)
return(NULL);
JS_SetOptions(js_cx, startup->js.options);
JS_BEGINREQUEST(js_cx);
lprintf(LOG_DEBUG,"%04d JavaScript: Context created",session->socket);
lprintf(LOG_DEBUG,"%04d JavaScript: Context created with options: %lx"
,session->socket, (long)startup->js.options);
JS_SetErrorReporter(js_cx, js_ErrorReporter);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment