Bug 1857488 - Add the RTPCallerType to JS realms. r=jandem

Differential Revision: https://phabricator.services.mozilla.com/D190676
This commit is contained in:
Tom Schuster 2023-10-26 17:49:00 +00:00
Родитель f6676f428f
Коммит 5ef6bee795
7 изменённых файлов: 75 добавлений и 33 удалений

Просмотреть файл

@ -33,6 +33,7 @@
#include "mozilla/MathAlgorithms.h" // mozilla::Abs
#include "js/Conversions.h" // JS::ToInteger
#include "js/RealmOptions.h" // JS::RTPCallerTypeToken
#include "js/TypeDecls.h"
#include "js/Value.h" // JS::CanonicalizeNaN, JS::DoubleValue, JS::Value
@ -187,15 +188,26 @@ JS_PUBLIC_API double DayFromYear(double year);
JS_PUBLIC_API double DayWithinYear(double time, double year);
// The callback will be a wrapper function that accepts a double (the time
// to clamp and jitter). Inside the JS Engine, other parameters that may be
// needed are all constant, so they are handled inside the wrapper function
using ReduceMicrosecondTimePrecisionCallback = double (*)(double, JSContext*);
// to clamp and jitter) and a JS::RTPCallerTypeToken (a wrapper for
// mozilla::RTPCallerType) that can be used to decide the proper clamping
// behavior to use. Inside the JS Engine, other parameters that may be needed
// are all constant, so they are handled inside the wrapper function
using ReduceMicrosecondTimePrecisionCallback =
double (*)(double, JS::RTPCallerTypeToken, JSContext*);
// Set a callback into the toolkit/components/resistfingerprinting function that
// will centralize time resolution and jitter into one place.
// Defining such a callback requires all Realms that are created afterwards
// to have a set JS::RTPCallerTypeToken, via RealmBehaviors or
// JS::SetRealmReduceTimerPrecisionCallerType.
JS_PUBLIC_API void SetReduceMicrosecondTimePrecisionCallback(
ReduceMicrosecondTimePrecisionCallback callback);
// Get the previously set ReduceMicrosecondTimePrecisionCallback callback or
// nullptr.
JS_PUBLIC_API ReduceMicrosecondTimePrecisionCallback
GetReduceMicrosecondTimePrecisionCallback();
// Sets the time resolution for fingerprinting protection, and whether jitter
// should occur. If resolution is set to zero, then no rounding or jitter will
// occur. This is used if the callback above is not specified.

Просмотреть файл

@ -14,6 +14,7 @@
#define js_RealmOptions_h
#include "mozilla/Assertions.h" // MOZ_ASSERT
#include "mozilla/Maybe.h"
#include "jstypes.h" // JS_PUBLIC_API
@ -320,6 +321,12 @@ class JS_PUBLIC_API RealmCreationOptions {
bool alwaysUseFdlibm_ = false;
};
// This is a wrapper for mozilla::RTPCallerType, that can't easily
// be exposed to the JS engine for layering reasons.
struct RTPCallerTypeToken {
uint8_t value;
};
/**
* RealmBehaviors specifies behaviors of a realm that can be changed after the
* realm's been created.
@ -328,6 +335,17 @@ class JS_PUBLIC_API RealmBehaviors {
public:
RealmBehaviors() = default;
// When a JS::ReduceMicrosecondTimePrecisionCallback callback is defined via
// JS::SetReduceMicrosecondTimePrecisionCallback, a JS::RTPCallerTypeToken (a
// wrapper for mozilla::RTPCallerType) needs to be set for every Realm.
mozilla::Maybe<RTPCallerTypeToken> reduceTimerPrecisionCallerType() const {
return rtpCallerType;
}
RealmBehaviors& setReduceTimerPrecisionCallerType(RTPCallerTypeToken type) {
rtpCallerType = mozilla::Some(type);
return *this;
}
// For certain globals, we know enough about the code that will run in them
// that we can discard script source entirely.
bool discardSource() const { return discardSource_; }
@ -342,29 +360,6 @@ class JS_PUBLIC_API RealmBehaviors {
return *this;
}
class Override {
public:
Override() : mode_(Default) {}
bool get(bool defaultValue) const {
if (mode_ == Default) {
return defaultValue;
}
return mode_ == ForceTrue;
}
void set(bool overrideValue) {
mode_ = overrideValue ? ForceTrue : ForceFalse;
}
void reset() { mode_ = Default; }
private:
enum Mode { Default, ForceTrue, ForceFalse };
Mode mode_;
};
// A Realm can stop being "live" in all the ways that matter before its global
// is actually GCed. Consumers that tear down parts of a Realm or its global
// before that point should set isNonLive accordingly.
@ -375,6 +370,7 @@ class JS_PUBLIC_API RealmBehaviors {
}
private:
mozilla::Maybe<RTPCallerTypeToken> rtpCallerType;
bool discardSource_ = false;
bool clampAndJitterTime_ = true;
bool isNonLive_ = false;
@ -423,6 +419,11 @@ extern JS_PUBLIC_API const RealmBehaviors& RealmBehaviorsRef(JSContext* cx);
extern JS_PUBLIC_API void SetRealmNonLive(Realm* realm);
// This behaves like RealmBehaviors::setReduceTimerPrecisionCallerType, but
// can be used even after the Realm has already been created.
extern JS_PUBLIC_API void SetRealmReduceTimerPrecisionCallerType(
Realm* realm, RTPCallerTypeToken type);
} // namespace JS
#endif // js_RealmOptions_h

Просмотреть файл

@ -46,6 +46,7 @@
#include "js/CompileOptions.h"
#include "js/ContextOptions.h" // JS::ContextOptions{,Ref}
#include "js/Conversions.h"
#include "js/Date.h" // JS::GetReduceMicrosecondTimePrecisionCallback
#include "js/ErrorInterceptor.h"
#include "js/ErrorReport.h" // JSErrorBase
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
@ -1761,6 +1762,11 @@ const JS::RealmBehaviors& JS::RealmBehaviorsRef(JSContext* cx) {
void JS::SetRealmNonLive(Realm* realm) { realm->setNonLive(); }
void JS::SetRealmReduceTimerPrecisionCallerType(Realm* realm,
JS::RTPCallerTypeToken type) {
realm->setReduceTimerPrecisionCallerType(type);
}
JS_PUBLIC_API JSObject* JS_NewGlobalObject(JSContext* cx, const JSClass* clasp,
JSPrincipals* principals,
JS::OnNewGlobalHookOption hookOption,
@ -1817,7 +1823,18 @@ JS_PUBLIC_API void JS_FireOnNewGlobalObject(JSContext* cx,
// This infallibility will eat OOM and slow script, but if that happens
// we'll likely run up into them again soon in a fallible context.
cx->check(global);
Rooted<js::GlobalObject*> globalObject(cx, &global->as<GlobalObject>());
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
if (JS::GetReduceMicrosecondTimePrecisionCallback()) {
MOZ_DIAGNOSTIC_ASSERT(globalObject->realm()
->behaviors()
.reduceTimerPrecisionCallerType()
.isSome(),
"Trying to create a global without setting an "
"explicit RTPCallerType!");
}
#endif
DebugAPI::onNewGlobalObject(cx, globalObject);
cx->runtime()->ensureRealmIsRecordingAllocations(globalObject);
}

Просмотреть файл

@ -498,6 +498,11 @@ JS_PUBLIC_API void JS::SetReduceMicrosecondTimePrecisionCallback(
sReduceMicrosecondTimePrecisionCallback = callback;
}
JS_PUBLIC_API JS::ReduceMicrosecondTimePrecisionCallback
JS::GetReduceMicrosecondTimePrecisionCallback() {
return sReduceMicrosecondTimePrecisionCallback;
}
JS_PUBLIC_API void JS::SetTimeResolutionUsec(uint32_t resolution, bool jitter) {
sResolutionUsec = resolution;
sJitter = jitter;
@ -1856,7 +1861,9 @@ static ClippedTime NowAsMillis(JSContext* cx) {
double now = PRMJ_Now();
bool clampAndJitter = cx->realm()->behaviors().clampAndJitterTime();
if (clampAndJitter && sReduceMicrosecondTimePrecisionCallback) {
now = sReduceMicrosecondTimePrecisionCallback(now, cx);
now = sReduceMicrosecondTimePrecisionCallback(
now, cx->realm()->behaviors().reduceTimerPrecisionCallerType().value(),
cx);
} else if (clampAndJitter && sResolutionUsec) {
double clamped = floor(now / sResolutionUsec) * sResolutionUsec;

Просмотреть файл

@ -471,6 +471,9 @@ class JS::Realm : public JS::shadow::Realm {
const JS::RealmBehaviors& behaviors() const { return behaviors_; }
void setNonLive() { behaviors_.setNonLive(); }
void setReduceTimerPrecisionCallerType(JS::RTPCallerTypeToken type) {
behaviors_.setReduceTimerPrecisionCallerType(type);
}
/* Whether to preserve JIT code on non-shrinking GCs. */
bool preserveJitCode() { return creationOptions_.preserveJitCode(); }

Просмотреть файл

@ -661,13 +661,14 @@ double nsRFPService::ReduceTimePrecisionAsSecsRFPOnly(
}
/* static */
double nsRFPService::ReduceTimePrecisionAsUSecsWrapper(double aTime,
JSContext* aCx) {
double nsRFPService::ReduceTimePrecisionAsUSecsWrapper(
double aTime, JS::RTPCallerTypeToken aCallerType, JSContext* aCx) {
MOZ_ASSERT(aCx);
nsCOMPtr<nsIGlobalObject> global = xpc::CurrentNativeGlobal(aCx);
MOZ_ASSERT(global);
RTPCallerType callerType = global->GetRTPCallerType();
return nsRFPService::ReduceTimePrecisionImpl(
aTime, MicroSeconds, TimerResolution(callerType),
0, /* For absolute timestamps (all the JS engine does), supply zero

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/BasicEvents.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/TypedEnumBits.h"
#include "js/RealmOptions.h"
#include "nsHashtablesFwd.h"
#include "nsICookieJarSettings.h"
#include "nsIFingerprintingWebCompatService.h"
@ -197,10 +198,6 @@ class nsRFPService final : public nsIObserver, public nsIRFPService {
static double ReduceTimePrecisionAsSecsRFPOnly(double aTime,
int64_t aContextMixin,
RTPCallerType aRTPCallerType);
// Used by the JS Engine, as it doesn't know about the TimerPrecisionType enum
static double ReduceTimePrecisionAsUSecsWrapper(double aTime, JSContext* aCx);
// Public only for testing purposes
static double ReduceTimePrecisionImpl(double aTime, TimeScale aTimeScale,
double aResolutionUSec,
@ -348,6 +345,10 @@ class nsRFPService final : public nsIObserver, public nsIRFPService {
// --------------------------------------------------------------------------
// Used by the JS Engine
static double ReduceTimePrecisionAsUSecsWrapper(
double aTime, JS::RTPCallerTypeToken aCallerType, JSContext* aCx);
static TimerPrecisionType GetTimerPrecisionType(RTPCallerType aRTPCallerType);
static TimerPrecisionType GetTimerPrecisionTypeRFPOnly(