зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1677045 - Replace JS_MORE_DETERMINISTIC with a runtime flag. r=jandem
Differential Revision: https://phabricator.services.mozilla.com/D96973
This commit is contained in:
Родитель
b8d4e0b10e
Коммит
d491828238
|
@ -456,22 +456,6 @@ set_define("JS_MASM_VERBOSE", depends_if("--enable-masm-verbose")(lambda _: True
|
|||
set_config("JS_MASM_VERBOSE", depends_if("--enable-masm-verbose")(lambda _: True))
|
||||
|
||||
|
||||
option(
|
||||
"--enable-more-deterministic",
|
||||
env="JS_MORE_DETERMINISTIC",
|
||||
help="Enable changes that make the shell more deterministic",
|
||||
)
|
||||
|
||||
|
||||
@depends("--enable-more-deterministic")
|
||||
def more_deterministic(value):
|
||||
if value:
|
||||
return True
|
||||
|
||||
|
||||
set_define("JS_MORE_DETERMINISTIC", more_deterministic)
|
||||
|
||||
|
||||
# CTypes
|
||||
# =======================================================
|
||||
@depends(js_standalone)
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
|
||||
#include "js/PropertySpec.h"
|
||||
#include "js/Wrapper.h"
|
||||
#include "util/DifferentialTesting.h"
|
||||
#include "util/Windows.h"
|
||||
#include "vm/ArrayBufferObject.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
|
@ -455,12 +456,10 @@ bool DataViewObject::write(JSContext* cx, Handle<DataViewObject*> obj,
|
|||
return false;
|
||||
}
|
||||
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
// See the comment in ElementSpecific::doubleToNative.
|
||||
if (TypeIsFloatingPoint<NativeType>()) {
|
||||
if (js::SupportDifferentialTesting() && TypeIsFloatingPoint<NativeType>()) {
|
||||
value = JS::CanonicalizeNaN(value);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Step 6.
|
||||
bool isLittleEndian = args.length() >= 3 && ToBoolean(args[2]);
|
||||
|
|
|
@ -89,6 +89,7 @@
|
|||
# include "unicode/utypes.h"
|
||||
# include "unicode/uversion.h"
|
||||
#endif
|
||||
#include "util/DifferentialTesting.h"
|
||||
#include "util/StringBuffer.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/AsyncFunction.h"
|
||||
|
@ -418,15 +419,6 @@ static bool GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
value = BooleanValue(true);
|
||||
#else
|
||||
value = BooleanValue(false);
|
||||
#endif
|
||||
if (!JS_SetProperty(cx, info, "more-deterministic", value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef MOZ_PROFILING
|
||||
value = BooleanValue(true);
|
||||
#else
|
||||
|
@ -588,9 +580,7 @@ static bool GC(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef JS_MORE_DETERMINISTIC
|
||||
size_t preBytes = cx->runtime()->gc.heapSize.bytes();
|
||||
#endif
|
||||
|
||||
if (zone) {
|
||||
PrepareForDebugGC(cx->runtime());
|
||||
|
@ -601,10 +591,10 @@ static bool GC(JSContext* cx, unsigned argc, Value* vp) {
|
|||
JS::NonIncrementalGC(cx, gckind, reason);
|
||||
|
||||
char buf[256] = {'\0'};
|
||||
#ifndef JS_MORE_DETERMINISTIC
|
||||
SprintfLiteral(buf, "before %zu, after %zu\n", preBytes,
|
||||
cx->runtime()->gc.heapSize.bytes());
|
||||
#endif
|
||||
if (!js::SupportDifferentialTesting()) {
|
||||
SprintfLiteral(buf, "before %zu, after %zu\n", preBytes,
|
||||
cx->runtime()->gc.heapSize.bytes());
|
||||
}
|
||||
return ReturnStringCopy(cx, args, buf);
|
||||
}
|
||||
|
||||
|
@ -3059,11 +3049,11 @@ static bool DumpHeap(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
|
||||
static bool Terminate(JSContext* cx, unsigned arg, Value* vp) {
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
// Print a message to stderr in more-deterministic builds to help jsfunfuzz
|
||||
// Print a message to stderr in differential testing to help jsfunfuzz
|
||||
// find uncatchable-exception bugs.
|
||||
fprintf(stderr, "terminate called\n");
|
||||
#endif
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
fprintf(stderr, "terminate called\n");
|
||||
}
|
||||
|
||||
JS_ClearPendingException(cx);
|
||||
return false;
|
||||
|
@ -3948,16 +3938,18 @@ static bool DetachArrayBuffer(JSContext* cx, unsigned argc, Value* vp) {
|
|||
|
||||
static bool HelperThreadCount(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
// Always return 0 to get consistent output with and without --no-threads.
|
||||
args.rval().setInt32(0);
|
||||
#else
|
||||
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
// Always return 0 to get consistent output with and without --no-threads.
|
||||
args.rval().setInt32(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CanUseExtraThreads()) {
|
||||
args.rval().setInt32(HelperThreadState().threadCount);
|
||||
} else {
|
||||
args.rval().setInt32(0);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4040,6 +4032,14 @@ static bool SharedArrayRawBufferRefcount(JSContext* cx, unsigned argc,
|
|||
#ifdef NIGHTLY_BUILD
|
||||
static bool ObjectAddress(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
RootedObject callee(cx, &args.callee());
|
||||
ReportUsageErrorASCII(cx, callee,
|
||||
"Function unavailable in differential testing mode.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args.length() != 1) {
|
||||
RootedObject callee(cx, &args.callee());
|
||||
ReportUsageErrorASCII(cx, callee, "Wrong number of arguments");
|
||||
|
@ -4051,20 +4051,23 @@ static bool ObjectAddress(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
# ifdef JS_MORE_DETERMINISTIC
|
||||
args.rval().setInt32(0);
|
||||
return true;
|
||||
# else
|
||||
void* ptr = js::UncheckedUnwrap(&args[0].toObject(), true);
|
||||
char buffer[64];
|
||||
SprintfLiteral(buffer, "%p", ptr);
|
||||
|
||||
return ReturnStringCopy(cx, args, buffer);
|
||||
# endif
|
||||
}
|
||||
|
||||
static bool SharedAddress(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
RootedObject callee(cx, &args.callee());
|
||||
ReportUsageErrorASCII(cx, callee,
|
||||
"Function unavailable in differential testing mode.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args.length() != 1) {
|
||||
RootedObject callee(cx, &args.callee());
|
||||
ReportUsageErrorASCII(cx, callee, "Wrong number of arguments");
|
||||
|
@ -4076,9 +4079,6 @@ static bool SharedAddress(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
# ifdef JS_MORE_DETERMINISTIC
|
||||
args.rval().setString(cx->staticStrings().getUint(0));
|
||||
# else
|
||||
RootedObject obj(cx, CheckedUnwrapStatic(&args[0].toObject()));
|
||||
if (!obj) {
|
||||
ReportAccessDenied(cx);
|
||||
|
@ -4100,7 +4100,6 @@ static bool SharedAddress(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
|
||||
args.rval().setString(str);
|
||||
# endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -6106,14 +6105,12 @@ static bool BaselineCompile(JSContext* cx, unsigned argc, Value* vp) {
|
|||
|
||||
const char* returnedStr = nullptr;
|
||||
do {
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
// In order to check for differential behaviour, baselineCompile should have
|
||||
// the same output whether --no-baseline is used or not.
|
||||
if (fuzzingSafe) {
|
||||
returnedStr = "skipped (fuzzing-safe)";
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
returnedStr = "skipped (differential testing)";
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
AutoRealm ar(cx, script);
|
||||
if (script->hasBaselineScript()) {
|
||||
|
|
|
@ -233,6 +233,7 @@
|
|||
#include "js/Object.h" // JS::GetClass
|
||||
#include "js/SliceBudget.h"
|
||||
#include "proxy/DeadObjectProxy.h"
|
||||
#include "util/DifferentialTesting.h"
|
||||
#include "util/Poison.h"
|
||||
#include "util/Windows.h"
|
||||
#include "vm/BigIntType.h"
|
||||
|
@ -6941,7 +6942,10 @@ GCRuntime::IncrementalResult GCRuntime::budgetIncrementalGC(
|
|||
}
|
||||
|
||||
void GCRuntime::maybeIncreaseSliceBudget(SliceBudget& budget) {
|
||||
#ifndef JS_MORE_DETERMINISTIC
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Increase time budget for long-running incremental collections. Enforce a
|
||||
// minimum time budget that increases linearly with time/slice count up to a
|
||||
// maximum.
|
||||
|
@ -6966,7 +6970,6 @@ void GCRuntime::maybeIncreaseSliceBudget(SliceBudget& budget) {
|
|||
budget = SliceBudget(TimeBudget(minBudget));
|
||||
}
|
||||
}
|
||||
#endif // JS_MORE_DETERMINISTIC
|
||||
}
|
||||
|
||||
static void ScheduleZones(GCRuntime* gc) {
|
||||
|
@ -8524,7 +8527,7 @@ static bool ZoneGCNumberGetter(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
#ifdef DEBUG
|
||||
static bool DummyGetter(JSContext* cx, unsigned argc, Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
args.rval().setUndefined();
|
||||
|
@ -8554,11 +8557,14 @@ JSObject* NewMemoryInfoObject(JSContext* cx) {
|
|||
{"sliceCount", GCSliceCountGetter}};
|
||||
|
||||
for (auto pair : getters) {
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
JSNative getter = DummyGetter;
|
||||
#else
|
||||
JSNative getter = pair.getter;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
getter = DummyGetter;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!JS_DefineProperty(cx, obj, pair.name, getter, nullptr,
|
||||
JSPROP_ENUMERATE)) {
|
||||
return nullptr;
|
||||
|
@ -8585,11 +8591,14 @@ JSObject* NewMemoryInfoObject(JSContext* cx) {
|
|||
{"gcNumber", ZoneGCNumberGetter}};
|
||||
|
||||
for (auto pair : zoneGetters) {
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
JSNative getter = DummyGetter;
|
||||
#else
|
||||
JSNative getter = pair.getter;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
getter = DummyGetter;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!JS_DefineProperty(cx, zoneObj, pair.name, getter, nullptr,
|
||||
JSPROP_ENUMERATE)) {
|
||||
return nullptr;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "gc/PublicIterators.h"
|
||||
#include "jit/JitFrames.h"
|
||||
#include "jit/JitRealm.h"
|
||||
#include "util/DifferentialTesting.h"
|
||||
#include "util/Poison.h"
|
||||
#include "vm/ArrayObject.h"
|
||||
#include "vm/JSONPrinter.h"
|
||||
|
@ -219,9 +220,7 @@ js::Nursery::Nursery(GCRuntime* gc)
|
|||
canAllocateBigInts_(true),
|
||||
reportTenurings_(0),
|
||||
minorGCTriggerReason_(JS::GCReason::NO_REASON),
|
||||
#ifndef JS_MORE_DETERMINISTIC
|
||||
smoothedGrowthFactor(1.0),
|
||||
#endif
|
||||
decommitTask(gc)
|
||||
#ifdef JS_GC_ZEAL
|
||||
,
|
||||
|
@ -1552,13 +1551,11 @@ size_t js::Nursery::targetSize(JSGCInvocationKind kind, JS::GCReason reason) {
|
|||
|
||||
// Calculate the fraction of time spent collecting the nursery.
|
||||
double timeFraction = 0.0;
|
||||
#ifndef JS_MORE_DETERMINISTIC
|
||||
if (lastResizeTime) {
|
||||
if (lastResizeTime && !js::SupportDifferentialTesting()) {
|
||||
TimeDuration collectorTime = now - collectionStartTime();
|
||||
TimeDuration totalTime = now - lastResizeTime;
|
||||
timeFraction = collectorTime.ToSeconds() / totalTime.ToSeconds();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Adjust the nursery size to try to achieve a target promotion rate and
|
||||
// collector time goals.
|
||||
|
@ -1572,17 +1569,16 @@ size_t js::Nursery::targetSize(JSGCInvocationKind kind, JS::GCReason reason) {
|
|||
static const double GrowthRange = 2.0;
|
||||
growthFactor = ClampDouble(growthFactor, 1.0 / GrowthRange, GrowthRange);
|
||||
|
||||
#ifndef JS_MORE_DETERMINISTIC
|
||||
// Use exponential smoothing on the desired growth rate to take into account
|
||||
// the promotion rate from recent previous collections.
|
||||
if (lastResizeTime &&
|
||||
now - lastResizeTime < TimeDuration::FromMilliseconds(200)) {
|
||||
now - lastResizeTime < TimeDuration::FromMilliseconds(200) &&
|
||||
!js::SupportDifferentialTesting()) {
|
||||
growthFactor = 0.75 * smoothedGrowthFactor + 0.25 * growthFactor;
|
||||
}
|
||||
|
||||
lastResizeTime = now;
|
||||
smoothedGrowthFactor = growthFactor;
|
||||
#endif
|
||||
|
||||
// Leave size untouched if we are close to the promotion goal.
|
||||
static const double GoalWidth = 1.5;
|
||||
|
@ -1599,10 +1595,12 @@ size_t js::Nursery::targetSize(JSGCInvocationKind kind, JS::GCReason reason) {
|
|||
}
|
||||
|
||||
void js::Nursery::clearRecentGrowthData() {
|
||||
#ifndef JS_MORE_DETERMINISTIC
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastResizeTime = TimeStamp();
|
||||
smoothedGrowthFactor = 1.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
|
|
@ -518,10 +518,8 @@ class Nursery {
|
|||
};
|
||||
PreviousGC previousGC;
|
||||
|
||||
#ifndef JS_MORE_DETERMINISTIC
|
||||
mozilla::TimeStamp lastResizeTime;
|
||||
double smoothedGrowthFactor;
|
||||
#endif
|
||||
|
||||
// Calculate the promotion rate of the most recent minor GC.
|
||||
// The valid_for_tenuring parameter is used to return whether this
|
||||
|
|
|
@ -318,6 +318,7 @@
|
|||
#include "js/HeapAPI.h"
|
||||
#include "js/SliceBudget.h"
|
||||
#include "threading/ProtectedData.h"
|
||||
#include "util/DifferentialTesting.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
|
@ -669,11 +670,13 @@ class GCSchedulingState {
|
|||
void updateHighFrequencyMode(const mozilla::TimeStamp& lastGCTime,
|
||||
const mozilla::TimeStamp& currentTime,
|
||||
const GCSchedulingTunables& tunables) {
|
||||
#ifndef JS_MORE_DETERMINISTIC
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
return;
|
||||
}
|
||||
|
||||
inHighFrequencyGCMode_ =
|
||||
!lastGCTime.IsNull() &&
|
||||
lastGCTime + tunables.highFrequencyThreshold() > currentTime;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "js/RegExpFlags.h"
|
||||
#include "js/Value.h"
|
||||
#include "threading/ExclusiveData.h"
|
||||
#include "util/DifferentialTesting.h"
|
||||
#include "vm/JSContext.h"
|
||||
#include "vm/MutexIDs.h"
|
||||
#include "vm/NativeObject.h"
|
||||
|
@ -1094,14 +1095,12 @@ class StackLimitCheck {
|
|||
// Use this to check for stack-overflows in C++ code.
|
||||
bool HasOverflowed() {
|
||||
bool overflowed = !js::CheckRecursionLimitDontReport(cx_);
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
if (overflowed) {
|
||||
if (overflowed && js::SupportDifferentialTesting()) {
|
||||
// We don't report overrecursion here, but we throw an exception later
|
||||
// and this still affects differential testing. Mimic ReportOverRecursed
|
||||
// (the fuzzers check for this particular string).
|
||||
fprintf(stderr, "ReportOverRecursed called\n");
|
||||
}
|
||||
#endif
|
||||
return overflowed;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "js/ScalarType.h" // js::Scalar::Type
|
||||
#include "js/Value.h"
|
||||
#include "js/Vector.h"
|
||||
#include "util/DifferentialTesting.h"
|
||||
#include "vm/ArrayObject.h"
|
||||
#include "vm/BuiltinObjectKind.h"
|
||||
#include "vm/EnvironmentObject.h"
|
||||
|
@ -5418,11 +5419,7 @@ class MRandom : public MNullaryInstruction {
|
|||
CompactBufferWriter& writer) const override;
|
||||
|
||||
bool canRecoverOnBailout() const override {
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
return !js::SupportDifferentialTesting();
|
||||
}
|
||||
|
||||
ALLOW_CLONE(MRandom)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "jit/CompileWrappers.h"
|
||||
#include "jit/JitFrames.h"
|
||||
#include "jit/JSJitFrameIter.h"
|
||||
#include "util/DifferentialTesting.h"
|
||||
#include "vm/ProxyObject.h"
|
||||
#include "vm/Runtime.h"
|
||||
|
||||
|
@ -810,10 +811,10 @@ void MacroAssembler::canonicalizeFloat(FloatRegister reg) {
|
|||
}
|
||||
|
||||
void MacroAssembler::canonicalizeFloatIfDeterministic(FloatRegister reg) {
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
// See the comment in TypedArrayObjectTemplate::getElement.
|
||||
canonicalizeFloat(reg);
|
||||
#endif // JS_MORE_DETERMINISTIC
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
canonicalizeFloat(reg);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::canonicalizeDouble(FloatRegister reg) {
|
||||
|
@ -824,10 +825,10 @@ void MacroAssembler::canonicalizeDouble(FloatRegister reg) {
|
|||
}
|
||||
|
||||
void MacroAssembler::canonicalizeDoubleIfDeterministic(FloatRegister reg) {
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
// See the comment in TypedArrayObjectTemplate::getElement.
|
||||
canonicalizeDouble(reg);
|
||||
#endif // JS_MORE_DETERMINISTIC
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
canonicalizeDouble(reg);
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "jit/JitRuntime.h"
|
||||
#include "jit/RangeAnalysis.h"
|
||||
#include "js/ScalarType.h" // js::Scalar::Type
|
||||
#include "util/DifferentialTesting.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
|
@ -2152,7 +2153,11 @@ void CodeGeneratorX86Shared::visitOutOfLineWasmTruncateCheck(
|
|||
|
||||
void CodeGeneratorX86Shared::canonicalizeIfDeterministic(
|
||||
Scalar::Type type, const LAllocation* value) {
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
#ifdef DEBUG
|
||||
if (!js::SupportDifferentialTesting()) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case Scalar::Float32: {
|
||||
FloatRegister in = ToFloatRegister(value);
|
||||
|
@ -2169,7 +2174,7 @@ void CodeGeneratorX86Shared::canonicalizeIfDeterministic(
|
|||
break;
|
||||
}
|
||||
}
|
||||
#endif // JS_MORE_DETERMINISTIC
|
||||
#endif // DEBUG
|
||||
}
|
||||
|
||||
void CodeGenerator::visitCopySignF(LCopySignF* lir) {
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
#include "js/Wrapper.h"
|
||||
#include "proxy/DOMProxy.h"
|
||||
#include "util/CompleteFile.h"
|
||||
#include "util/DifferentialTesting.h"
|
||||
#include "util/StringBuffer.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/AsyncFunction.h"
|
||||
|
@ -5955,4 +5956,16 @@ JS_PUBLIC_API void NoteIntentionalCrash() {
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool gSupportDifferentialTesting = false;
|
||||
#endif // DEBUG
|
||||
|
||||
} // namespace js
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
JS_PUBLIC_API void JS::SetSupportDifferentialTesting(bool value) {
|
||||
js::gSupportDifferentialTesting = value;
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
|
|
@ -3019,4 +3019,12 @@ enum class CompletionKind { Normal, Return, Throw };
|
|||
|
||||
} /* namespace js */
|
||||
|
||||
#ifdef DEBUG
|
||||
namespace JS {
|
||||
|
||||
extern JS_PUBLIC_API void SetSupportDifferentialTesting(bool value);
|
||||
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
#endif /* jsapi_h */
|
||||
|
|
|
@ -145,6 +145,7 @@
|
|||
#include "threading/LockGuard.h"
|
||||
#include "threading/Thread.h"
|
||||
#include "util/CompleteFile.h" // js::FileContents, js::ReadCompleteFile
|
||||
#include "util/DifferentialTesting.h"
|
||||
#include "util/StringBuffer.h"
|
||||
#include "util/Text.h"
|
||||
#include "util/Windows.h"
|
||||
|
@ -2880,11 +2881,11 @@ static bool Help(JSContext* cx, unsigned argc, Value* vp);
|
|||
static bool Quit(JSContext* cx, unsigned argc, Value* vp) {
|
||||
ShellContext* sc = GetShellContext(cx);
|
||||
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
// Print a message to stderr in more-deterministic builds to help jsfunfuzz
|
||||
// Print a message to stderr in differential testing to help jsfunfuzz
|
||||
// find uncatchable-exception bugs.
|
||||
fprintf(stderr, "quit called\n");
|
||||
#endif
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
fprintf(stderr, "quit called\n");
|
||||
}
|
||||
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
int32_t code;
|
||||
|
@ -5589,6 +5590,14 @@ static bool DumpStencil(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
|
||||
static bool Parse(JSContext* cx, unsigned argc, Value* vp) {
|
||||
// Parse returns local scope information with variables ordered
|
||||
// differently, depending on the underlying JIT implementation.
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
JS_ReportErrorASCII(cx,
|
||||
"Function not available in differential testing mode.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return FrontendTest(cx, argc, vp, "parse", DumpType::ParseNode);
|
||||
}
|
||||
|
||||
|
@ -7727,6 +7736,12 @@ static bool DumpScopeChain(JSContext* cx, unsigned argc, Value* vp) {
|
|||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
RootedObject callee(cx, &args.callee());
|
||||
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
ReportUsageErrorASCII(
|
||||
cx, callee, "Function not available in differential testing mode.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args.length() != 1) {
|
||||
ReportUsageErrorASCII(cx, callee, "Wrong number of arguments");
|
||||
return false;
|
||||
|
@ -7761,11 +7776,7 @@ static bool DumpScopeChain(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef JS_MORE_DETERMINISTIC
|
||||
// Don't dump anything in more-deterministic builds because the output
|
||||
// includes pointer values.
|
||||
script->bodyScope()->dump();
|
||||
#endif
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
|
@ -11003,6 +11014,12 @@ static int Shell(JSContext* cx, OptionParser* op, char** envp) {
|
|||
(getenv("MOZ_FUZZING_SAFE") && getenv("MOZ_FUZZING_SAFE")[0] != '0');
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (op->getBoolOption("differential-testing")) {
|
||||
JS::SetSupportDifferentialTesting(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (op->getBoolOption("disable-oom-functions")) {
|
||||
disableOOMFunctions = true;
|
||||
}
|
||||
|
@ -11455,6 +11472,11 @@ int main(int argc, char** argv, char** envp) {
|
|||
!op.addBoolOption('\0', "fuzzing-safe",
|
||||
"Don't expose functions that aren't safe for "
|
||||
"fuzzers to call") ||
|
||||
#ifdef DEBUG
|
||||
!op.addBoolOption('\0', "differential-testing",
|
||||
"Avoid random/undefined behavior that disturbs "
|
||||
"differential testing (correctness fuzzing)") ||
|
||||
#endif
|
||||
!op.addBoolOption('\0', "disable-oom-functions",
|
||||
"Disable functions that cause "
|
||||
"artificial OOMs") ||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* Definitions for differential testing.
|
||||
*/
|
||||
|
||||
#ifndef util_DifferentialTesting_h
|
||||
#define util_DifferentialTesting_h
|
||||
|
||||
namespace js {
|
||||
|
||||
inline bool SupportDifferentialTesting() {
|
||||
#ifdef DEBUG
|
||||
extern bool gSupportDifferentialTesting;
|
||||
return gSupportDifferentialTesting;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* util_DifferentialTesting_h */
|
|
@ -38,6 +38,7 @@
|
|||
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
|
||||
#include "js/Printf.h"
|
||||
#include "js/Symbol.h"
|
||||
#include "util/DifferentialTesting.h"
|
||||
#include "util/Memory.h"
|
||||
#include "util/StringBuffer.h"
|
||||
#include "util/Text.h"
|
||||
|
@ -2363,14 +2364,14 @@ static bool DecompileExpressionFromStack(JSContext* cx, int spindex,
|
|||
|
||||
*res = nullptr;
|
||||
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
/*
|
||||
* Give up if we need deterministic behavior for differential testing.
|
||||
* IonMonkey doesn't use InterpreterFrames and this ensures we get the same
|
||||
* error messages.
|
||||
*/
|
||||
return true;
|
||||
#endif
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (spindex == JSDVG_IGNORE_STACK) {
|
||||
return true;
|
||||
|
@ -2461,10 +2462,10 @@ static bool DecompileArgumentFromStack(JSContext* cx, int formalIndex,
|
|||
|
||||
*res = nullptr;
|
||||
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
/* See note in DecompileExpressionFromStack. */
|
||||
return true;
|
||||
#endif
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Settle on the nearest script frame, which should be the builtin that
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
|
||||
#include "js/PropertySpec.h"
|
||||
#include "js/Proxy.h"
|
||||
#include "util/DifferentialTesting.h"
|
||||
#include "util/Poison.h"
|
||||
#include "vm/BytecodeUtil.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
|
@ -375,14 +376,17 @@ static bool EnumerateProxyProperties(JSContext* cx, HandleObject pobj,
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
#ifdef DEBUG
|
||||
|
||||
struct SortComparatorIds {
|
||||
JSContext* const cx;
|
||||
|
||||
SortComparatorIds(JSContext* cx) : cx(cx) {}
|
||||
explicit SortComparatorIds(JSContext* cx) : cx(cx) {}
|
||||
|
||||
bool operator()(jsid aArg, jsid bArg, bool* lessOrEqualp) {
|
||||
RootedId a(cx, aArg);
|
||||
RootedId b(cx, bArg);
|
||||
|
||||
bool operator()(jsid a, jsid b, bool* lessOrEqualp) {
|
||||
// Pick an arbitrary order on jsids that is as stable as possible
|
||||
// across executions.
|
||||
if (a == b) {
|
||||
|
@ -390,8 +394,8 @@ struct SortComparatorIds {
|
|||
return true;
|
||||
}
|
||||
|
||||
size_t ta = JSID_BITS(a) & JSID_TYPE_MASK;
|
||||
size_t tb = JSID_BITS(b) & JSID_TYPE_MASK;
|
||||
size_t ta = JSID_BITS(a.get()) & JSID_TYPE_MASK;
|
||||
size_t tb = JSID_BITS(b.get()) & JSID_TYPE_MASK;
|
||||
if (ta != tb) {
|
||||
*lessOrEqualp = (ta <= tb);
|
||||
return true;
|
||||
|
@ -444,7 +448,7 @@ struct SortComparatorIds {
|
|||
}
|
||||
};
|
||||
|
||||
#endif /* JS_MORE_DETERMINISTIC */
|
||||
#endif /* DEBUG */
|
||||
|
||||
static bool Snapshot(JSContext* cx, HandleObject pobj_, unsigned flags,
|
||||
MutableHandleIdVector props) {
|
||||
|
@ -514,37 +518,37 @@ static bool Snapshot(JSContext* cx, HandleObject pobj_, unsigned flags,
|
|||
}
|
||||
} while (pobj != nullptr);
|
||||
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
#ifdef DEBUG
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
/*
|
||||
* In some cases the enumeration order for an object depends on the
|
||||
* execution mode (interpreter vs. JIT), especially for native objects
|
||||
* with a class enumerate hook (where resolving a property changes the
|
||||
* resulting enumeration order). These aren't really bugs, but the
|
||||
* differences can change the generated output and confuse correctness
|
||||
* fuzzers, so we sort the ids if such a fuzzer is running.
|
||||
*
|
||||
* We don't do this in the general case because (a) doing so is slow,
|
||||
* and (b) it also breaks the web, which expects enumeration order to
|
||||
* follow the order in which properties are added, in certain cases.
|
||||
* Since ECMA does not specify an enumeration order for objects, both
|
||||
* behaviors are technically correct to do.
|
||||
*/
|
||||
|
||||
/*
|
||||
* In some cases the enumeration order for an object depends on the
|
||||
* execution mode (interpreter vs. JIT), especially for native objects
|
||||
* with a class enumerate hook (where resolving a property changes the
|
||||
* resulting enumeration order). These aren't really bugs, but the
|
||||
* differences can change the generated output and confuse correctness
|
||||
* fuzzers, so we sort the ids if such a fuzzer is running.
|
||||
*
|
||||
* We don't do this in the general case because (a) doing so is slow,
|
||||
* and (b) it also breaks the web, which expects enumeration order to
|
||||
* follow the order in which properties are added, in certain cases.
|
||||
* Since ECMA does not specify an enumeration order for objects, both
|
||||
* behaviors are technically correct to do.
|
||||
*/
|
||||
jsid* ids = props.begin();
|
||||
size_t n = props.length();
|
||||
|
||||
jsid* ids = props.begin();
|
||||
size_t n = props.length();
|
||||
RootedIdVector tmp(cx);
|
||||
if (!tmp.resize(n)) {
|
||||
return false;
|
||||
}
|
||||
PodCopy(tmp.begin(), ids, n);
|
||||
|
||||
RootedIdVector tmp(cx);
|
||||
if (!tmp.resize(n)) {
|
||||
return false;
|
||||
if (!MergeSort(ids, n, tmp.begin(), SortComparatorIds(cx))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
PodCopy(tmp.begin(), ids, n);
|
||||
|
||||
if (!MergeSort(ids, n, tmp.begin(), SortComparatorIds(cx))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* JS_MORE_DETERMINISTIC */
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "js/friend/StackLimits.h" // js::ReportOverRecursed
|
||||
#include "js/Printf.h"
|
||||
#include "util/DiagnosticAssertions.h"
|
||||
#include "util/DifferentialTesting.h"
|
||||
#include "util/DoubleToString.h"
|
||||
#include "util/NativeStack.h"
|
||||
#include "util/Windows.h"
|
||||
|
@ -246,14 +247,14 @@ bool AutoResolving::alreadyStartedSlow() const {
|
|||
* not occur, so GC must be avoided or suppressed.
|
||||
*/
|
||||
JS_FRIEND_API void js::ReportOutOfMemory(JSContext* cx) {
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
/*
|
||||
* OOMs are non-deterministic, especially across different execution modes
|
||||
* (e.g. interpreter vs JIT). In more-deterministic builds, print to stderr
|
||||
* (e.g. interpreter vs JIT). When doing differential testing, print to stderr
|
||||
* so that the fuzzers can detect this.
|
||||
*/
|
||||
fprintf(stderr, "ReportOutOfMemory called\n");
|
||||
#endif
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
fprintf(stderr, "ReportOutOfMemory called\n");
|
||||
}
|
||||
|
||||
if (cx->isHelperThreadContext()) {
|
||||
return cx->addPendingOutOfMemory();
|
||||
|
@ -283,7 +284,6 @@ mozilla::GenericErrorResult<OOM> js::ReportOutOfMemoryResult(JSContext* cx) {
|
|||
}
|
||||
|
||||
void js::ReportOverRecursed(JSContext* maybecx, unsigned errorNumber) {
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
/*
|
||||
* We cannot make stack depth deterministic across different
|
||||
* implementations (e.g. JIT vs. interpreter will differ in
|
||||
|
@ -292,8 +292,10 @@ void js::ReportOverRecursed(JSContext* maybecx, unsigned errorNumber) {
|
|||
* stack depth which is useful for external testing programs
|
||||
* like fuzzers.
|
||||
*/
|
||||
fprintf(stderr, "ReportOverRecursed called\n");
|
||||
#endif
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
fprintf(stderr, "ReportOverRecursed called\n");
|
||||
}
|
||||
|
||||
if (maybecx) {
|
||||
if (!maybecx->isHelperThreadContext()) {
|
||||
JS_ReportErrorNumberASCII(maybecx, GetErrorMessage, nullptr, errorNumber);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "js/PropertySpec.h"
|
||||
#include "js/SavedFrameAPI.h"
|
||||
#include "js/Vector.h"
|
||||
#include "util/DifferentialTesting.h"
|
||||
#include "util/StringBuffer.h"
|
||||
#include "vm/GeckoProfiler.h"
|
||||
#include "vm/JSScript.h"
|
||||
|
@ -193,9 +194,9 @@ struct MOZ_STACK_CLASS SavedFrame::Lookup {
|
|||
activation(activation) {
|
||||
MOZ_ASSERT(source);
|
||||
MOZ_ASSERT_IF(framePtr.isSome(), activation);
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
column = 0;
|
||||
#endif
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
column = 0;
|
||||
}
|
||||
}
|
||||
|
||||
explicit Lookup(SavedFrame& savedFrame)
|
||||
|
@ -482,9 +483,9 @@ void SavedFrame::initLine(uint32_t line) {
|
|||
}
|
||||
|
||||
void SavedFrame::initColumn(uint32_t column) {
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
column = 0;
|
||||
#endif
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
column = 0;
|
||||
}
|
||||
initReservedSlot(JSSLOT_COLUMN, PrivateUint32Value(column));
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "js/Conversions.h"
|
||||
#include "js/ScalarType.h" // js::Scalar::Type
|
||||
#include "js/Value.h"
|
||||
#include "util/DifferentialTesting.h"
|
||||
#include "util/Memory.h"
|
||||
#include "vm/BigIntType.h"
|
||||
#include "vm/JSContext.h"
|
||||
|
@ -719,14 +720,14 @@ class ElementSpecific {
|
|||
|
||||
static T doubleToNative(double d) {
|
||||
if (TypeIsFloatingPoint<T>()) {
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
// The JS spec doesn't distinguish among different NaN values, and
|
||||
// it deliberately doesn't specify the bit pattern written to a
|
||||
// typed array when NaN is written into it. This bit-pattern
|
||||
// inconsistency could confuse deterministic testing, so always
|
||||
// canonicalize NaN values in more-deterministic builds.
|
||||
d = JS::CanonicalizeNaN(d);
|
||||
#endif
|
||||
// inconsistency could confuse differential testing, so always
|
||||
// canonicalize NaN values in differential testing.
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
d = JS::CanonicalizeNaN(d);
|
||||
}
|
||||
return T(d);
|
||||
}
|
||||
if (MOZ_UNLIKELY(mozilla::IsNaN(d))) {
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "js/ScalarType.h" // js::Scalar::Type
|
||||
#include "js/UniquePtr.h"
|
||||
#include "js/Wrapper.h"
|
||||
#include "util/DifferentialTesting.h"
|
||||
#include "util/Text.h"
|
||||
#include "util/Windows.h"
|
||||
#include "vm/ArrayBufferObject.h"
|
||||
|
@ -973,10 +974,10 @@ bool TypedArrayObjectTemplate<NativeType>::convertValue(JSContext* cx,
|
|||
return false;
|
||||
}
|
||||
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
// See the comment in ElementSpecific::doubleToNative.
|
||||
d = JS::CanonicalizeNaN(d);
|
||||
#endif
|
||||
if (js::SupportDifferentialTesting()) {
|
||||
// See the comment in ElementSpecific::doubleToNative.
|
||||
d = JS::CanonicalizeNaN(d);
|
||||
}
|
||||
|
||||
// Assign based on characteristics of the destination type
|
||||
if constexpr (ArrayTypeIsFloatingPoint()) {
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "js/SourceText.h"
|
||||
#include "js/StableStringChars.h"
|
||||
#include "js/Wrapper.h"
|
||||
#include "util/DifferentialTesting.h"
|
||||
#include "util/StringBuffer.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/ErrorReporting.h"
|
||||
|
@ -6983,13 +6984,9 @@ static bool NoExceptionPending(JSContext* cx) {
|
|||
|
||||
static bool SuccessfulValidation(frontend::ParserBase& parser,
|
||||
unsigned compilationTime) {
|
||||
constexpr unsigned errNum =
|
||||
#ifdef JS_MORE_DETERMINISTIC
|
||||
JSMSG_USE_ASM_TYPE_OK_NO_TIME
|
||||
#else
|
||||
JSMSG_USE_ASM_TYPE_OK
|
||||
#endif
|
||||
;
|
||||
unsigned errNum = js::SupportDifferentialTesting()
|
||||
? JSMSG_USE_ASM_TYPE_OK_NO_TIME
|
||||
: JSMSG_USE_ASM_TYPE_OK;
|
||||
|
||||
char timeChars[20];
|
||||
SprintfLiteral(timeChars, "%u", compilationTime);
|
||||
|
|
Загрузка…
Ссылка в новой задаче