|
3 | 3 | This document describes how to port your code from using one ESR version |
4 | 4 | of SpiderMonkey to the next ESR version. |
5 | 5 |
|
| 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 | +
|
6 | 157 | ## ESR 102 to ESR 115 ## |
7 | 158 |
|
8 | 159 | ### More Versatile `JS_InitClass` ### |
|
0 commit comments