SpiderMonkey was updated to mozjs24. If you want to build elinks
with ecmascript support, you must compile using g++ with -fpermissive .
There is a lot of warnings.
There are some memleaks in ecmascript code, especially related to JSAutoCompartment.
I don't know yet, where and how to free it.
Debian does not support mozjs24, so I'm going to gradually update SpiderMonkey version.
Weak points:
- alignof
- js problems
Todo:
- make js work with C++ and mozjs-17
- then mozjs-24
- then mozjs-52
- then mozjs-60
- decrease number of warnings
Each C function that can be called as a method of an ECMAScript object
is typically listed in a spidermonkeyFunctionSpec array and has a
comment that shows the name of the array and the name of the method.
For example, elinks_alert has a comment /* @elinks_funcs{"alert"} */
because elinks_funcs[] contains an element { "alert", elinks_alert, 1 }.
When some of those functions were split into outer and inner functions
for SpiderMonkey 1.8.5 compatibility, the comments were attached to
the inner functions, which contain the bulk of the code. Move the
comments to the outer functions, to which the array elements point.
forms_item declared a variable (jsval val), passed its address to
forms_item2, and set it as the return value. However, forms_item2
could return without initializing the jsval, especially if given too
many arguments. Fix by initializing to JSVAL_VOID right away.
I'm not sure that is the correct value to return in such cases,
but at least it's better than risking a crash.
Likewise in form_elements_item and form_elements_namedItem.
INIT_OPTION used to initialize union option_value at compile time by
casting the default value to LIST_OF(struct option) *, which is the
type of the first member. On sparc64 and other big-endian systems
where sizeof(int) < sizeof(struct list_head *), this tended to leave
option->value.number as zero, thus messing up OPT_INT and OPT_BOOL
at least. OPT_LONG however tended to work right.
This would be easy to fix with C99 designated initializers,
but doc/hacking.txt says ELinks must be kept C89 compatible.
Another solution would be to make register_options() read the
value from option->value.tree (the first member), cast it back
to the right type, and write it to the appropriate member;
but that would still require somewhat dubious conversions
between integers, data pointers, and function pointers.
So here's a rather more invasive solution. Add struct option_init,
which is somewhat similar to struct option but has non-overlapping
members for different types of values, to ensure nothing is lost
in compile-time conversions. Move unsigned char *path from struct
option_info to struct option_init, and replace struct option_info
with a union that contains struct option_init and struct option.
Now, this union can be initialized with no portability problems,
and register_options() then moves the values from struct option_init
to their final places in struct option.
In my x86 ELinks build with plenty of options configured in, this
change bloated the text section by 340 bytes but compressed the data
section by 2784 bytes, presumably because union option_info is a
pointer smaller than struct option_info was.
(cherry picked from elinks-0.12 commit e5f6592ee2)
Conflicts:
src/protocol/fsp/fsp.c: All options had been removed in 0.13.GIT.
src/protocol/smb/smb2.c: Ditto.
Add session_class, which defines a JSObject wrapper for struct session.
Add location_array_class, which defines a JSObject wrapper for struct
ses_history. The "history" member of struct session is a struct
ses_history, which is a linked list of struct location.
Add a pointer from struct session to the session_class object and the
location_array object.
Add smjs_get_session_object to return a session_class JSObject wrapper for
a given struct session.
Add smjs_get_session_location_array_object to return a location_array_class
JSObject wrapper for a given struct session.
Add "session" property to the "elinks" object, which uses
smjs_get_session_object to get a JSObject wrapper for smjs_ses.
Add smjs_location_array_get_property, which allows indexing
a location_array object using a positive number for history forward or
a negative number for history backward.
Add session_props, session_get_property, session_set_property,
session_funcs, smjs_session_goto_url (which implements the "goto" method),
and smjs_init_session_interface for session_class.
Add session_construct, which creates a new tab and returns the JSObject
session_class wrapper.
Add session_finalize and smjs_location_array_finalize, which clear the
pointers between struct session and the JSObject wrappers in question.
Add smjs_detach_session_object, which clears the pointers between a given
struct session and the corresponding JSObject wrappers.
In destroy_session, call smjs_detach_session_object.
Add jsval_to_object helper in ecmascript/spidermonkey/util.h;
jsval_to_object is used in smjs_session_goto_url.
Modify delayed_goto_uri_frame to allow the target to be NULL.
smjs_session_goto_url needs this modification.
Add an include for config/options.h to src/ecmascript/spidermonkey.c
and two missing declarations (struct form_view and struct form_state)
to src/ecmascript/spidermonkey.h.
Implement new heartbeat code to catch runaway execution of document
ECMAScript code. The old code uses JS_SetBranchCallback which is
deprecated in new versions of SpiderMonkey. The new code uses setitimer(2)
and the JS_SetOperationCallback and JS_TriggerOperationCallback interfaces,
introduced in SpiderMonkey 1.8.1. Compatibility with both the old
JS_SetBranchCallback and the new interfaces is maintained.
This should fix a crash in:
at /home/Kalle/src/elinks-0.12/src/ecmascript/spidermonkey.c:251
at /home/Kalle/src/elinks-0.12/src/ecmascript/ecmascript.c:104
at /home/Kalle/src/elinks-0.12/src/viewer/text/vs.c:64
It seems that spidermonkey_get_interpreter failed and returned NULL to
ecmascript_get_interpreter, which did not check the return value and
behaved as if the ECMAScript interpreter had been properly initialized.
This caused destroy_vs to call ecmascript_put_interpreter, but
backend_data which should have been a JSContext * was NULL, causing
a crash in SpiderMonkey.
An alternative fix might be to make spidermonkey_put_interpreter skip
the JS_DestroyContext call if ctx is NULL. However, I think it is
better to make sure ecmascript_get_interpreter returns NULL if
spidermonkey_get_interpreter fails, so that vs->ecmascript is left
NULL and there's no chance that some other code might try to
dereference the (JSContext *) NULL.
Perhaps because of bug 981, if one opened hundreds of pages with
elinks --remote openURL(...), then ELinks 0.11.4 could crash with a
SIGSEGV in JS_InitClass called from spidermonkey_get_interpreter.
SpiderMonkey ran out of memory and began returning NULL and JS_FALSE
but ELinks didn't notice them and pressed on. Add some checks to
avoid the crash, although the underlying out-of-memory error remains.
Documentation strings of most options used to contain a "\n" at the
end of each source line. When the option manager displayed these
strings, it treated each "\n" as a hard newline. On 80x24 terminals
however, the option description window has only 60 columes available
for the text (with the default setup.h), and the hard newlines were
further apart, so the option manager wrapped the text a second time,
resulting in rather ugly output where long lones are interleaved with
short ones. This could also cause the text to take up too much
vertical space and not fit in the window.
Replace most of those hard newlines with spaces so that the option
manager (or perhaps BFU) will take care of the wrapping. At the same
time, rewrap the strings in source code so that the source lines are
at most 79 columns wide.
In some options though, there is a list of possible values and their
meanings. In those lists, if the description of one value does not
fit in one line, then continuation lines should be indented. The
option manager and BFU are not currently able to do that. So, keep
the hard newlines in those lists, but rewrap them to 60 columns so
that they are less likely to require further wrapping at runtime.
This reverts commit b94657869b.
I don't know where I got the idea that JS_SetErrorReporter affects the
entire JSRuntime, rather than only the provided JSContext. The people
on #jsapi say it has never worked that way.
Except if they have external handlers.
When ELinks receives an event from a terminal, move that terminal to
the beginning of the global "terminals" list, so that the terminals
are always sorted according to the time of the most recent use. Note,
this affects the numbering of bookmark folders in session snapshots.
Add get_default_terminal(), which returns the most recently used
terminal that is still open. Use that in various places that
previously used terminals.prev or terminals.next. Four functions
fetch the size of the terminal for User-Agent headers, and
get_default_terminal() is not really right, but neither was the
original code; add TODO comments in those functions.
When the user chooses "Background and Notify", associate the download
with the terminal where the dialog box is. So any later messages will
then appear in that terminal, if it is still open. However, don't
change the terminal if the download has an external handler.
When a download gets some data, don't immediately check the associated
terminal. Instead, wait for the download to end. Then, if the
terminal of the download has been closed, use get_default_terminal()
instead. If there is no default terminal either, just skip any
message boxes.
Previously, spidermonkey_get_interpreter() and init_smjs() each called
JS_SetErrorReporter on the JSContexts they created. However,
JS_SetErrorReporter actually sets the error reporter of the JSRuntime
associated with the JSContext, and all of our JSContexts use the same
JSRuntime nowadays, so only the error_reporter() of
src/ecmascript/spidermonkey.c was left installed. Because this
error_reporter() asserts that JS_GetContextPrivate(ctx) returns a
non-NULL pointer, and init_smjs() does not set a private pointer for
smjs_ctx, any error in smjs_ctx could cause an assertion failure, at
least in principle.
Fix this by making spidermonkey_runtime_addref() install a shared
error_reporter() when it creates the JSRuntime and the first JSContext.
The shared error_reporter() then checks the JSContext and calls the
appropriate function.
The two error reporters are quite similar with each other. In the
future, we could move the common code into shared functions. I'm not
doing that yet though, because fixing the bug doesn't require it.
Introduce static int interpreter_count in src/ecmascript/ecmascript.c.
Maintain interpreter_count in ecmascript_get_interpreter and
ecmascript_put_interpreter.
Introduce ecmascript_get_interpreter_count.
Display the number of ECMAScript interpreters that have been allocated
for documents in the Resources dialog box.
cache_entry.id => cache_entry.cache_id
document.id => document.cache_id
ecmascript_interpreter.onload_snippets_owner => .onload_snippets_cache_id
This is a combination of:
commit 232c07aa7f
bug 1009: id variables renamed, added document_id to the document.
commit 6007043458bf8f14abfc18b9db60785bdc0279f6
Revert addition of document.document_id
init_js_window_object() copies the alert, open, and setTimeout methods
from the window object to the global object. My fix for bug 846 on
2006-12-10 incorrectly made the corresponding C functions refuse to
work if they were not called as methods of the window object.
JSObject instances of input_class now again contain a private pointer
directly to struct form_state. This pointer is cleared or updated
when appropriate.
Anything that frees struct form_view must now call the new function
ecmascript_detach_form_view. This function should then clear out any
dangling pointers, but that has not yet been implemented.
Anything that frees or reallocates struct form_state must now call the
new functions ecmascript_detach_form_state or ecmascript_moved_form_state.
These functions should then clear out any dangling pointers, but that has
not yet been implemented.
Rename src/ecmascript/spidermonkey/util.c to
src/ecmascript/spidermonkey-shared.c and compile it also when
CONFIG_SCRIPTING_SMJS is enabled but CONFIG_ECMASCRIPT_SPIDERMONKEY is
not. Then use its functions from src/scripting/smjs/ too. Move the
corresponding declarations, as well as the inline functions needed by
src/scripting/smjs/, from src/ecmascript/spidermonkey/util.h to
src/ecmascript/spidermonkey-shared.h.
ELinks is nowadays using two JSRuntimes and SpiderMonkey has bugs that
make it crash in such use. To work around them, ELinks will need to
be changed to use only one JSRuntime. I am planning to define and
initialize that JSRuntime in src/ecmascript/spidermonkey-shared.c,
now that it's compiled whenever either of the modules is enabled.
Conflicts:
NEWS
configure.in
The following files also conflicted, but they had not been manually
edited in the elinks-0.12 branch after the previous merge, so I just
kept the 0.13.GIT versions:
doc/man/man1/elinks.1.in
doc/man/man5/elinks.conf.5
doc/man/man5/elinkskeys.5
po/fr.po
po/pl.po
cached->id => cached->cache_id
document->id => document->cache_id
onload_snippets_owner => onload_snippets_document_id
Added the distinct document->document_id.
Always reset ecmascript when a document changes for example a next chunk
of it is loaded.
Pass the session with some get_opt_* calls. These are the low-hanging fruit. Some places will be difficult because we don't have the session or for other reasons.
There were conflicts in src/document/css/ because 0.12.GIT switched
to LIST_OF(struct css_selector) and 0.13.GIT switched to struct
css_selector_set. Resolved by using LIST_OF(struct css_selector)
inside struct css_selector_set.
The previous code cast the integer (long actually) to void * and gave
that to JS_SetPrivate. This did not work because JS_SetPrivate
expects pointers to be aligned and replaces the least significant bit
with a tag. By using JS_SetReservedSlot instead, we get control of
the jsval conversions and can store the integer properly.
Add ecmascript_interpreter.backend_nesting, increment it when
beginning to evaluate an expression, and decrement it when evaluation
finishes. Then assert that it is zero in ecmascript_put_interpreter.
This detects bug 957 and similar ones before they corrupt memory.
Although <see/object.h> of SEE 2.0.1131 has a comment saying that
SEE_objectclass.enumerator is optional and may be left NULL, SEE
crashes if one tries to enumerate the properties of an object created
from such a class. Conveniently, it provides a suitable stub function.
http://www.adaptive-enterprises.com.au/bugs/show_bug.cgi?id=75
This is a further precaution against reading a pointer from the wrong
type of object. All of the JS_GetPrivate calls were already protected
with JS_InstanceOf checks if assertions are enabled, and many of them
also if assertions are not enabled.
Remember the index of struct form_state in vs->form_info
instead of the pointer to it. The pointer may change,
the index is persistent.
The field ecmascript_obj of the struct form_state is unused.
Previously, html_special_form_control converted
form_control.default_value to the terminal charset, and init_form_state
then copied the value to form_state.value. However, when CONFIG_UTF8
is defined and UTF-8 I/O is enabled, form_state.value is supposed to
be in UTF-8, rather than in the terminal charset.
This mismatch could not be conveniently fixed in
html_special_form_control because that does not know which terminal is
being used and whether UTF-8 I/O is enabled there. Also, constructing
a conversion table from the document charset to form_state.value could
have ruined renderer_context.convert_table, because src/intl/charsets.c
does not support multiple concurrent conversion tables.
So instead, we now keep form_control.default_value in the document
charset, and convert it in the viewer each time it is needed. Because
the result of the conversion is kept in form_state.value between
incremental renderings, this shouldn't even slow things down too much.
I am not implementing the proper charset conversions for the DOM
defaultValue property yet, because the current code doesn't have
them for other string properties either, and bug 805 is already open
for that.
straconcat reads the args with va_arg(ap, const unsigned char *),
and the NULL macro may have the wrong type (e.g. int).
Many places pass string literals of type char * to straconcat. This
is in principle also a violation, but I'm ignoring it for now because
if it becomes a problem with some C implementation, then so will the
use of unsigned char * with printf "%s", which is so widespread in
ELinks that I'm not going to try fixing it now.
This change does not fix any bug, but the SMJS builtin classes use
negative tinyids already, so I presume this is the preferred practice.
At least it means the tinyids won't have to be renumbered later if
some of these objects are changed to behave as arrays.
If ECMAScript code does obj[42], then the getProperty or setProperty
function of the JSClass of obj gets 42 as the property ID and must not
treat that as an internal error.
The getProperty and setProperty functions of a JSClass must not assume
that the obj parameter points to an instance of that class. It might
instead point to another object that merely has an instance of the
class in its prototype chain. Thus, do not assert that JS_InstanceOf
returns true there. Instead, run the check even with CONFIG_FASTMEM,
and just return JS_FALSE if it fails.
Otherwise if the page installs multiple timers the old one would live
on unreferenced and possibly (likely) trigger after the document's death
and everything would go to hell.
Surrogates are now treated the same way as out-of-range characters
like U+110000; if a link has such an access key, then the ECMAScript
accessKey property cannot be read. It seems currently impossible to
set such an access key though, because accesskey_string_to_unicode()
doesn't support multibyte characters yet.
Create and immediately destroy a context when initialising the SMJS
document scripting module, because SMJS crashes on exit if there has
been no context created since it started, which is the case if one does
not load any documents.
Replace the ECMAScript module initialisation and de-initialisation
routines that wrapped the SMJS and SEE module initialisation and
de-initialisation routines by having the module system call the SMJS
and SEE routines its own darned self.
Assign deo->target a copy of target instead of target itself because
delayed_goto_uri_frame frees deo->target and SpiderMonkey owns target.
Reported by Jonas.
The two copies of delayed_open in src/ecmascript/spidermonkey/window.c
and in src/ecmascript/see/window.c are identical, so move them
to src/terminal/tab.c and eliminate the duplication.
Until the last change in src/ecmascript/see/window.c, the two copies
of delayed_goto_uri_frame in src/ecmascript/spidermonkey/window.c and
in src/ecmascript/see/window.c were identical. That change applies to
both versions, so move the newer one to src/session/task.c and eliminate
the duplication. Also move struct delayed_open to src/session/session.h.
This changes the init target to be idempotent: most importantly it will now
never overwrite a Makefile if it exists. Additionally 'make init' will
generate the .vimrc files. Yay, no more stupid 'added fairies' commits! ;)
Convert remaining conditional file building to use
OBJS-$(CONFIG_FOO) += foo.o
one problem with reverse meaining (in util/) fixed with local 'hack'.
Cleanup and remove stuff which is now default targets.
It is a little ugly since I couldn't get $(wildcard) to expand *.o files
so it just checks if there are any *.c files and then link in the lib.o
based on that.
Ditch the building of an archive (.a) in favour of linking all objects in a
directory into a lib.o file. This makes it easy to link in subdirectories
and more importantly keeps the build logic in the local subdirectories.
Note: after updating you will have to rm **/*.a if you do not make clean
before updating.
All objects defining $(OBJS) will get them and *.a deleted during
make clean.
The all, clean and install rules now implicitly imply their -recursive
counterparts - those will just do nothing in case of $(SUBDIRS) not
defined, so that's ok.
The root makefile is converted as well as some leaf Makefiles. This
also brings in the required infrastructure and adjusts configure.in
appropriately.
I converted only makefiles containing no configurable stuff, since
that'll require more consideration yet.