Skip to content

Commit a074e5a

Browse files
committed
Add support for retrieving the Engine from a JSContext
... and use that wherever we previously stored a pointer to the `Engine` in a static global. Signed-off-by: Till Schneidereit <till@tillschneidereit.net>
1 parent b4ccad4 commit a074e5a

File tree

5 files changed

+43
-23
lines changed

5 files changed

+43
-23
lines changed

builtins/web/fetch/fetch-api.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99

1010
namespace builtins::web::fetch {
1111

12-
static api::Engine *ENGINE;
13-
1412
// TODO: throw in all Request methods/getters that rely on host calls once a
1513
// request has been sent. The host won't let us act on them anymore anyway.
1614
/**
@@ -86,7 +84,8 @@ bool fetch(JSContext *cx, unsigned argc, Value *vp) {
8684
// If the request body is streamed, we need to wait for streaming to complete
8785
// before marking the request as pending.
8886
if (!streaming) {
89-
ENGINE->queue_async_task(new ResponseFutureTask(request_obj, pending_handle));
87+
api::Engine::from_context(cx)
88+
.queue_async_task(new ResponseFutureTask(request_obj, pending_handle));
9089
}
9190

9291
SetReservedSlot(request_obj, static_cast<uint32_t>(Request::Slots::ResponsePromise),
@@ -101,8 +100,6 @@ bool fetch(JSContext *cx, unsigned argc, Value *vp) {
101100
const JSFunctionSpec methods[] = {JS_FN("fetch", fetch, 2, JSPROP_ENUMERATE), JS_FS_END};
102101

103102
bool install(api::Engine *engine) {
104-
ENGINE = engine;
105-
106103
if (!JS_DefineFunctions(engine->cx(), engine->global(), methods))
107104
return false;
108105
if (!request_response::install(engine)) {

builtins/web/fetch/request-response.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ bool NativeStreamSource::stream_is_body(JSContext *cx, JS::HandleObject stream)
4141

4242
namespace builtins::web::fetch {
4343

44-
static api::Engine *ENGINE;
45-
4644
bool error_stream_controller_with_pending_exception(JSContext *cx, HandleObject controller) {
4745
RootedValue exn(cx);
4846
if (!JS_GetPendingException(cx, &exn))
@@ -466,7 +464,8 @@ bool finish_outgoing_body_streaming(JSContext* cx, HandleObject body_owner) {
466464
.toPrivate());
467465
SetReservedSlot(body_owner, static_cast<uint32_t>(Request::Slots::PendingResponseHandle),
468466
PrivateValue(nullptr));
469-
ENGINE->queue_async_task(new ResponseFutureTask(body_owner, pending_handle));
467+
api::Engine::from_context(cx)
468+
.queue_async_task(new ResponseFutureTask(body_owner, pending_handle));
470469
}
471470

472471
return true;
@@ -476,9 +475,10 @@ bool RequestOrResponse::append_body(JSContext *cx, JS::HandleObject self, JS::Ha
476475
MOZ_ASSERT(!body_used(source));
477476
MOZ_ASSERT(!body_used(self));
478477
MOZ_ASSERT(self != source);
478+
auto engine = api::Engine::from_context(cx);
479479
host_api::HttpIncomingBody *source_body = incoming_body_handle(source);
480480
host_api::HttpOutgoingBody *dest_body = outgoing_body_handle(self);
481-
auto res = dest_body->append(ENGINE, source_body, finish_outgoing_body_streaming, self);
481+
auto res = dest_body->append(&engine, source_body, finish_outgoing_body_streaming, self);
482482
if (auto *err = res.to_err()) {
483483
HANDLE_ERROR(cx, *err);
484484
return false;
@@ -892,7 +892,7 @@ bool RequestOrResponse::body_source_pull_algorithm(JSContext *cx, CallArgs args,
892892
}
893893
}
894894

895-
ENGINE->queue_async_task(new BodyFutureTask(source));
895+
api::Engine::from_context(cx).queue_async_task(new BodyFutureTask(source));
896896

897897
args.rval().setUndefined();
898898
return true;
@@ -945,7 +945,7 @@ bool reader_for_outgoing_body_then_handler(JSContext *cx, JS::HandleObject body_
945945
// Uint8Array?
946946
fprintf(stderr, "Error: read operation on body ReadableStream didn't respond with a "
947947
"Uint8Array. Received value: ");
948-
ENGINE->dump_value(val, stderr);
948+
api::Engine::from_context(cx).dump_value(val, stderr);
949949
return false;
950950
}
951951

@@ -985,7 +985,7 @@ bool reader_for_outgoing_body_catch_handler(JSContext *cx, JS::HandleObject body
985985
// stream errored during the streaming send. Not much we can do, but at least
986986
// close the stream, and warn.
987987
fprintf(stderr, "Warning: body ReadableStream closed during body streaming. Exception: ");
988-
ENGINE->dump_value(args.get(0), stderr);
988+
api::Engine::from_context(cx).dump_value(args.get(0), stderr);
989989

990990
return finish_outgoing_body_streaming(cx, body_owner);
991991
}
@@ -1004,7 +1004,8 @@ bool RequestOrResponse::maybe_stream_body(JSContext *cx, JS::HandleObject body_o
10041004
if (is_incoming(body_owner)) {
10051005
auto *source_body = incoming_body_handle(body_owner);
10061006
auto *dest_body = destination->body().unwrap();
1007-
auto res = dest_body->append(ENGINE, source_body, finish_outgoing_body_streaming, nullptr);
1007+
auto engine = api::Engine::from_context(cx);
1008+
auto res = dest_body->append(&engine, source_body, finish_outgoing_body_streaming, nullptr);
10081009
if (auto *err = res.to_err()) {
10091010
HANDLE_ERROR(cx, *err);
10101011
return false;
@@ -1233,7 +1234,7 @@ bool Request::clone(JSContext *cx, unsigned argc, JS::Value *vp) {
12331234
Value url_val = GetReservedSlot(self, static_cast<uint32_t>(Slots::URL));
12341235
SetReservedSlot(new_request, static_cast<uint32_t>(Slots::URL), url_val);
12351236
Value method_val = JS::StringValue(method(self));
1236-
ENGINE->dump_value(method_val, stderr);
1237+
api::Engine::from_context(cx).dump_value(method_val, stderr);
12371238
SetReservedSlot(new_request, static_cast<uint32_t>(Slots::Method), method_val);
12381239

12391240
// clone operation step 2.
@@ -2459,8 +2460,6 @@ JSObject * Response::create_incoming(JSContext *cx, host_api::HttpIncomingRespon
24592460
namespace request_response {
24602461

24612462
bool install(api::Engine *engine) {
2462-
ENGINE = engine;
2463-
24642463
if (!Request::init_class(engine->cx(), engine->global()))
24652464
return false;
24662465
if (!Response::init_class(engine->cx(), engine->global()))

builtins/web/timers.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ class TimersMap {
2828
}
2929

3030
static PersistentRooted<js::UniquePtr<TimersMap>> TIMERS_MAP;
31-
static api::Engine *ENGINE;
3231

3332
class TimerTask final : public api::AsyncTask {
3433
using TimerArgumentsVector = std::vector<JS::Heap<JS::Value>>;
@@ -119,12 +118,12 @@ class TimerTask final : public api::AsyncTask {
119118
}
120119
}
121120

122-
static bool clear(int32_t timer_id) {
121+
static bool clear(api::Engine &engine, int32_t timer_id) {
123122
if (!TIMERS_MAP->timers_.contains(timer_id)) {
124123
return false;
125124
}
126125

127-
ENGINE->cancel_async_task(TIMERS_MAP->timers_[timer_id]);
126+
engine.cancel_async_task(TIMERS_MAP->timers_[timer_id]);
128127
TIMERS_MAP->timers_.erase(timer_id);
129128
return true;
130129
}
@@ -171,7 +170,7 @@ template <bool repeat> bool setTimeout_or_interval(JSContext *cx, const unsigned
171170
}
172171

173172
const auto timer = new TimerTask(delay, repeat, handler, handler_args);
174-
ENGINE->queue_async_task(timer);
173+
api::Engine::from_context(cx).queue_async_task(timer);
175174
args.rval().setInt32(timer->timer_id());
176175

177176
return true;
@@ -193,7 +192,7 @@ template <bool interval> bool clearTimeout_or_interval(JSContext *cx, unsigned a
193192
return false;
194193
}
195194

196-
TimerTask::clear(id);
195+
TimerTask::clear(api::Engine::from_context(cx), id);
197196

198197
args.rval().setUndefined();
199198
return true;
@@ -206,7 +205,6 @@ constexpr JSFunctionSpec methods[] = {
206205
JS_FN("clearTimeout", clearTimeout_or_interval<false>, 1, JSPROP_ENUMERATE), JS_FS_END};
207206

208207
bool install(api::Engine *engine) {
209-
ENGINE = engine;
210208
TIMERS_MAP.init(engine->cx(), js::MakeUnique<TimersMap>());
211209
return JS_DefineFunctions(engine->cx(), engine->global(), methods);
212210
}

include/extension-api.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,27 @@ class Engine {
3636

3737
public:
3838
Engine();
39-
JSContext *cx();
39+
40+
/**
41+
* Returns the `JSContext` associated with the `Engine` instance.
42+
*
43+
* Currently, StarlingMonkey uses exactly one `Engine` and one `JSContext`. Since that might
44+
* change in the future, it's heavily recommended to not store either in static globals.
45+
*
46+
* @return The JSContext associated with the `Engine` instance
47+
*/
48+
JSContext *cx();
49+
50+
/**
51+
* Returns the `Engine` associated with the `JSContext` instance.
52+
*
53+
* Currently, StarlingMonkey uses exactly one `Engine` and one `JSContext`. Since that might
54+
* change in the future, it's heavily recommended to not store either in static globals.
55+
*
56+
* @return The `Engine` associated with the `JSContext` instance
57+
*/
58+
static Engine& from_context(JSContext *cx);
59+
4060
JS::HandleObject global();
4161

4262
/// Initialize the engine with the given filename

runtime/cpp/engine.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,12 @@ api::Engine::Engine() {
341341

342342
JSContext *api::Engine::cx() { return CONTEXT; }
343343

344+
api::Engine &api::Engine::from_context(JSContext *cx) {
345+
// This could also be implemented by storing the engine on the cx using JS_SetContextPrivate.
346+
// Since we're not supporting multiple contexts or engines, we can just return the global engine.
347+
return *ENGINE;
348+
}
349+
344350
HandleObject api::Engine::global() { return GLOBAL; }
345351

346352
extern bool install_builtins(api::Engine *engine);

0 commit comments

Comments
 (0)