Skip to content

Commit 31e6175

Browse files
committed
Migration from ESR 115 to 128
Includes updated build instructions and a migration guide. One of the examples needs to be updated, with the new column number API; and the WeakRefs example needs its job queue and realm creation options adjusted. Everything else builds as is.
1 parent ea93476 commit 31e6175

6 files changed

Lines changed: 169 additions & 17 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
This repository contains documentation and examples for people who want
44
to embed the SpiderMonkey JavaScript engine.
55

6-
The information on this `esr102` branch applies to SpiderMonkey 102.x, an
6+
The information on this `esr128` branch applies to SpiderMonkey 128.x, an
77
Extended Support Release (ESR).
88
For other versions of SpiderMonkey, check the other branches: `next` for
99
information that will apply in the next as-yet-unreleased ESR, or

docs/Building SpiderMonkey.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Use these instructions to build your own copy of SpiderMonkey.
55
## Prerequisites ##
66

77
You will need a **C++ compiler** that can handle the C++17 standard,
8-
**Rust** version [1.66][minimum-rust-version] or later, **GNU Make**,
8+
**Rust** version [1.76][minimum-rust-version] or later, **GNU Make**,
99
**zlib**, and **libffi**.
1010
These can usually be installed with a package manager.
1111

@@ -16,16 +16,16 @@ These can usually be installed with a package manager.
1616
> `--with-system-icu` in the build instructions below, for a shorter
1717
> build time.
1818
19-
[minimum-rust-version]: https://searchfox.org/mozilla-esr115/rev/61b47de1faebf23626e519b2464b461589fbea3e/python/mozboot/mozboot/util.py#14
20-
[minimum-icu-version]: https://searchfox.org/mozilla-esr115/rev/61b47de1faebf23626e519b2464b461589fbea3e/js/moz.configure#1107
19+
[minimum-rust-version]: https://searchfox.org/mozilla-esr128/rev/2d28d1b9e757a35095de45c818a0432e031f339d/python/mozboot/mozboot/util.py#14
20+
[minimum-icu-version]: https://searchfox.org/mozilla-esr128/rev/2d28d1b9e757a35095de45c818a0432e031f339d/js/moz.configure#1308
2121

2222
## Getting the source code ##
2323

2424
Currently, the most reliable way to get the SpiderMonkey source code is
2525
to download the Firefox source.
26-
At the time of writing, the latest source for Firefox ESR 115, which
27-
contains the source for SpiderMonkey ESR 115, can be found here:
28-
https://ftp.mozilla.org/pub/firefox/releases/115.1.0esr/source/
26+
At the time of writing, the latest source for Firefox ESR 128, which
27+
contains the source for SpiderMonkey ESR 128, can be found here:
28+
https://ftp.mozilla.org/pub/firefox/releases/128.1.0esr/source/
2929

3030
The ESR releases have a major release approximately once a year with
3131
security patches released throughout the year.

docs/Migration Guide.md

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,157 @@
33
This document describes how to port your code from using one ESR version
44
of SpiderMonkey to the next ESR version.
55

6+
## ESR 115 to ESR 128 ##
7+
8+
### New API for column numbers ###
9+
10+
Previously, column numbers (in source locations and stack frames) were
11+
stored as mostly as numbers starting from 0.
12+
When column numbers are shown in a user-facing context, however, they
13+
are usually displayed as starting at 1.
14+
SpiderMonkey has changed the internal representation of column numbers
15+
to start at 1 as well.
16+
There is a new set of APIs in `<js/ColumnNumber.h>` that allows
17+
explicitly converting from 1-origin to 0-origin in order to avoid
18+
confusion, and handles tagged column numbers from WASM frames.
19+
20+
**Recommendation:** You will need to use the new column number API if
21+
you obtain a column number from any stack frame API such as
22+
`JS::GetSavedFrameColumn()`.
23+
Example:
24+
25+
```c++
26+
// old
27+
uint32_t column;
28+
if (JS::GetSavedFrameColumn(cx, nullptr, frame, &column) != JS::SavedFrameResult::Ok)
29+
return false;
30+
std::cout << "column number " << column + 1;
31+
32+
// new
33+
JS::TaggedColumnNumberOneOrigin tagged_column;
34+
if (JS::GetSavedFrameColumn(cx, nullptr, frame, &tagged_column) != JS::SavedFrameResult::Ok)
35+
return false;
36+
std::cout << "column number " << tagged_column.oneOriginValue();
37+
```
38+
39+
The function `JS::CreateError()` takes a `JS::ColumnNumberOneOrigin`
40+
which is different from `JS::TaggedColumnNumberOneOrigin`.
41+
The "tagged" type exists to accommodate WASM frames, which have a
42+
function index instead of a column number.
43+
44+
If you don't have WASM frames, you can convert the tagged column to an
45+
untagged column number using:
46+
```c++
47+
JS::ColumnNumberOneOrigin{tagged_column.toLimitedColumnNumber()};
48+
```
49+
This will assert that the column number is not tagged as a WASM function
50+
index.
51+
If you have WASM frames, you'll need to handle those separately.
52+
53+
See [bug 1847469](https://bugzilla.mozilla.org/show_bug.cgi?id=1847469).
54+
55+
### New API for ArrayBuffer buffers ###
56+
57+
ArrayBuffer APIs that take data buffers from the embedding, such as
58+
`JS::NewExternalArrayBuffer()` and `JS::NewArrayBufferWithContents()`,
59+
now take a `mozilla::UniquePtr&&` argument for the data buffer.
60+
61+
**Recommendation:** This is a fairly straightforward migration, in which
62+
you can just put your data buffer into a UniquePtr and then
63+
`std::move()` it into the ArrayBuffer.
64+
If you previously passed a free callback, use that callback as the
65+
deleter argument to the UniquePtr.
66+
Examples:
67+
68+
```c++
69+
// old
70+
JS::RootedObject array_buffer{cx, JS::NewExternalArrayBuffer(
71+
cx, len, my_struct->buffer, my_buffer_free_func, my_struct)};
72+
73+
// new
74+
mozilla::UniquePtr<void, JS::BufferContentsDeleter> contents{
75+
my_struct->buffer, {my_buffer_free_func, my_struct}};
76+
JS::RootedObject array_buffer{cx, JS::NewExternalArrayBuffer(
77+
cx, len, std::move(contents))};
78+
```
79+
80+
### `JS::GCPolicy::needsSweep()` ###
81+
82+
`JS::GCPolicy<T>` has a new method, `needsSweep()`.
83+
It is like a const version of `JS::GCPolicy::traceWeak()`, but the sense
84+
of the boolean return value is reversed.
85+
(Returns true if the weak pointer is dead, and false if it is live.)
86+
The argument is const, so the method will not be called if the pointer
87+
needs to move.
88+
Implementing the method is optional.
89+
90+
**Recommendation:** If you have specialized `JS::GCPolicy` for any of
91+
your classes, consider whether you need to implement this method.
92+
If your class has a weak pointer, you probably do.
93+
94+
Also, note that `JS::GCPolicy<JS::Heap<T>>` does not implement
95+
`needsSweep()`.
96+
If you were storing a `JS::Heap` inside `JS::WeakCache<T>`, you will
97+
need to use a different data structure.
98+
An easy drop-in replacement for `JS::Heap` suitable for this purpose
99+
would be something like this:
100+
101+
```c++
102+
template <typename T>
103+
class WeakPtr : public JS::Heap<T> {
104+
public:
105+
using JS::Heap<T>::Heap;
106+
using JS::Heap<T>::operator=;
107+
};
108+
109+
namespace JS {
110+
111+
template <typename T>
112+
struct GCPolicy<WeakPtr<T>> {
113+
static void trace(JSTracer* trc, WeakPtr<T>* thingp, const char* name) {
114+
return JS::TraceEdge(trc, thingp, name);
115+
}
116+
117+
static bool traceWeak(JSTracer* trc, WeakPtr<T>* thingp) {
118+
return js::gc::TraceWeakEdge(trc, thingp);
119+
}
120+
121+
static bool needsSweep(JSTracer* trc, const WeakPtr<T>* thingp) {
122+
WeakPtr<T> thing{*thingp};
123+
return !js::gc::TraceWeakEdge(trc, &thing);
124+
}
125+
};
126+
127+
} // namespace JS
128+
```
129+
130+
### Getting Function IDs ###
131+
132+
`JS_GetFunctionId()` and `JS_GetFunctionDisplayId()` now require a
133+
JSContext.
134+
There are now alternatives that don't take a JSContext parameter, but
135+
avoid computing the full function name with "`get `" or "`set `" prefix
136+
for accessors: `JS_GetMaybePartialFunctionId()` and
137+
`JS_GetMaybePartialFunctionDisplayId()`.
138+
139+
**Recommendation:** The fact that these APIs didn't require a JSContext
140+
meant they were convenient to use for log output or debugging.
141+
If you were using them for this purpose, switch to the `MaybePartial`
142+
alternatives.
143+
Otherwise, just adapt to the new signature.
144+
145+
### Various API changes ###
146+
147+
This is a non-exhaustive list of minor API changes and renames.
148+
149+
- The type of `JSErrorBase::filename()` is now `JS::ConstUTF8CharsZ`
150+
instead of a C string, so when using `JSErrorReport` you will need to
151+
use `.c_str()` if you still need the C string.
152+
- Several runtime flags for new features in `JS::RealmCreationOptions`
153+
are enabled unconditionally, so the flags are removed.
154+
- Classes that extend `JS::JobQueue` must now implement
155+
`JS::JobQueue::isDrainingStopped()`, which is an abstract method.
156+
6157
## ESR 102 to ESR 115 ##
7158
8159
### More Versatile `JS_InitClass` ###

examples/cookbook.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <mozilla/Unused.h>
77

88
#include <js/Array.h>
9+
#include <js/ColumnNumber.h>
910
#include <js/CompilationAndEvaluation.h>
1011
#include <js/Conversions.h>
1112
#include <js/Initialization.h>
@@ -352,9 +353,10 @@ static bool ThrowValue(JSContext* cx, JS::HandleValue exc) {
352353
*
353354
* return ThrowError(cx, global, message, __FILE__, __LINE__, column);
354355
*/
355-
static bool ThrowError(JSContext* cx, JS::HandleObject global,
356-
const char* message, const char* filename,
357-
int32_t lineno, int32_t colno = 0) {
356+
static bool ThrowError(
357+
JSContext* cx, JS::HandleObject global, const char* message,
358+
const char* filename, int32_t lineno,
359+
JS::ColumnNumberOneOrigin colno = JS::ColumnNumberOneOrigin{1}) {
358360
JS::RootedString messageStr(cx, JS_NewStringCopyZ(cx, message));
359361
if (!messageStr) return false;
360362
JS::RootedString filenameStr(cx, JS_NewStringCopyZ(cx, filename));

examples/weakref.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ class CustomJobQueue : public JS::JobQueue {
118118
// JS::JobQueue override
119119
bool empty() const override { return m_queue.empty(); }
120120

121+
// JS::JobQueue override
122+
bool isDrainingStopped() const override { return !m_draining; }
123+
121124
void queueFinalizationRegistryCallback(JSFunction* callback) {
122125
mozilla::Unused << m_finalizationRegistryCallbacks.append(callback);
123126
}
@@ -247,16 +250,12 @@ static bool WeakRefExample(JSContext* cx) {
247250
JS::SetHostCleanupFinalizationRegistryCallback(
248251
cx, CleanupFinalizationRegistry, &jobQueue);
249252

250-
JS::RealmOptions options;
251-
options.creationOptions().setWeakRefsEnabled(
252-
JS::WeakRefSpecifier::EnabledWithoutCleanupSome);
253-
254253
static JSClass GlobalClass = {"WeakRefsGlobal", JSCLASS_GLOBAL_FLAGS,
255254
&JS::DefaultGlobalClassOps};
256255

257256
JS::Rooted<JSObject*> global{
258257
cx, JS_NewGlobalObject(cx, &GlobalClass, nullptr, JS::FireOnNewGlobalHook,
259-
options)};
258+
JS::RealmOptions{})};
260259
if (!global) return false;
261260

262261
JSAutoRealm ar{cx, global};

meson.build

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
project('spidermonkey-embedding-examples', 'cpp', version: 'esr115',
1+
project('spidermonkey-embedding-examples', 'cpp', version: 'esr128',
22
meson_version: '>= 0.43.0',
33
default_options: ['cpp_std=c++20', 'warning_level=3'])
44

@@ -7,7 +7,7 @@ cxx = meson.get_compiler('cpp')
77
args = []
88

99
zlib = dependency('zlib') # (is already a SpiderMonkey dependency)
10-
spidermonkey = dependency('mozjs-127a1')
10+
spidermonkey = dependency('mozjs-128')
1111
readline = cxx.find_library('readline')
1212

1313
# Check if SpiderMonkey was compiled with --enable-debug. If this is the case,

0 commit comments

Comments
 (0)