import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1171405 - Add baseline and ion ICs for GETELEM on unboxed plain objects, r=jandem. (1b83760e1)
- Bug 1094491 - Generate baseline getProp ICs for accessor properties before calling the getter. r=efaust (8fd5fbf93)
- Bug 1094491 - Generate baseline getGName ICs for accessor properties before calling the getter. r=efaust (6b2b1699f)
- Bug 1094491 - Add assertion in UpdateExistingGetPropCallStubs that should hold now. r=efaust (70c31131b)
- Bug 1038859 - Add symbol-support to Baseline GetElem ICs. r=djvj (e77aa66d3)
- Bug 1153458 - Fix decompiler issue with DoCallNativeGetter. r=efaust (dacb12a63)
- Bug 1145924 - Ensure JSRuntime is kept in sync with the profiler. (r=djvj) (d17e158d0)
- Bug 1156317 - Change the onOutOfMemory() interface is make it harder to misuse r=terrence (374165af5)
- Bug 1131043 - Part 3: Fix ecma_6/TypedArray/slice.js to check %TypedArray%[@@species] instead of Symbol.species. r=bustage (81a8342af)
- bits of Bug 761261 - Add JS profiling to SPS (7304b7e29)
- Bug 1164664 - Swap out the 'default JSContext callback' for something capable of setting up an AutoEntryScript. v3 r=jimb (16d44cea8)
- Bug 1164664 - Switch to new-style error-reporting for PrepareScriptEnvironment. r=jimb (32f6dbedf)
- Bug 1164664 - Defang PushJSContextNoScriptContext. r=jimb (60d3ce9e6)
- Bug 887030 - Remove the volatile from heapState; r=jonco (0bfe003a8)
- pointer style (eb2fba373)
- Bug 887030 - Allow inlining of heapState checks from outside JSAPI; r=jonco (02cd0c2d6)
- Bug 887030 - Remove JS::shadow::Runtime::needsIncrementalBarrier and use heapState directly; r=jonco (99d924c37)
This commit is contained in:
2020-11-06 11:12:50 +08:00
parent cad44081d6
commit 34bb7a462c
44 changed files with 1232 additions and 709 deletions
+1 -1
View File
@@ -2099,7 +2099,7 @@ static bool
ReportLargeAllocationFailure(JSContext* cx, unsigned argc, jsval* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
void* buf = cx->runtime()->onOutOfMemoryCanGC(NULL, JSRuntime::LARGE_ALLOCATION);
void* buf = cx->runtime()->onOutOfMemoryCanGC(AllocFunction::Malloc, JSRuntime::LARGE_ALLOCATION);
js_free(buf);
args.rval().setUndefined();
return true;
+30 -25
View File
@@ -335,6 +335,18 @@ namespace CClosure {
// libffi callback
static void ClosureStub(ffi_cif* cif, void* result, void** args,
void* userData);
struct ArgClosure : public ScriptEnvironmentPreparer::Closure {
ArgClosure(ffi_cif* cifArg, void* resultArg, void** argsArg, ClosureInfo* cinfoArg)
: cif(cifArg), result(resultArg), args(argsArg), cinfo(cinfoArg) {}
bool operator()(JSContext *cx) override;
ffi_cif* cif;
void* result;
void** args;
ClosureInfo* cinfo;
};
}
namespace CData {
@@ -6755,9 +6767,6 @@ CClosure::Create(JSContext* cx,
MOZ_ASSERT(proto);
MOZ_ASSERT(CType::IsCTypeProto(proto));
// Get a JSContext for use with the closure.
JSContext* closeureCx = js::DefaultJSContext(JS_GetRuntime(cx));
// Prepare the error sentinel value. It's important to do this now, because
// we might be unable to convert the value to the proper type. If so, we want
// the caller to know about it _now_, rather than some uncertain time in the
@@ -6794,7 +6803,6 @@ CClosure::Create(JSContext* cx,
}
// Copy the important bits of context into cinfo.
cinfo->cx = closeureCx;
cinfo->errResult = errResult.release();
cinfo->closureObj = result;
cinfo->typeObj = typeObj;
@@ -6865,9 +6873,14 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
MOZ_ASSERT(userData);
// Retrieve the essentials from our closure object.
ClosureInfo* cinfo = static_cast<ClosureInfo*>(userData);
JSContext* cx = cinfo->cx;
ArgClosure argClosure(cif, result, args, static_cast<ClosureInfo*>(userData));
JSRuntime* rt = argClosure.cinfo->rt;
RootedObject fun(rt, argClosure.cinfo->jsfnObj);
(void) js::PrepareScriptEnvironmentAndInvoke(rt, fun, argClosure);
}
bool CClosure::ArgClosure::operator()(JSContext* cx)
{
// Let the runtime callback know that we are about to call into JS again. The end callback will
// fire automatically when we exit this function.
js::AutoCTypesActivityCallback autoCallback(cx, js::CTYPES_CALLBACK_BEGIN,
@@ -6876,12 +6889,11 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
RootedObject typeObj(cx, cinfo->typeObj);
RootedObject thisObj(cx, cinfo->thisObj);
RootedValue jsfnVal(cx, ObjectValue(*cinfo->jsfnObj));
AssertSameCompartment(cx, cinfo->jsfnObj);
JS_AbortIfWrongThread(JS_GetRuntime(cx));
JSAutoRequest ar(cx);
JSAutoCompartment ac(cx, cinfo->jsfnObj);
// Assert that our CIFs agree.
FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
MOZ_ASSERT(cif == &fninfo->mCIF);
@@ -6914,7 +6926,7 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
JS::AutoValueVector argv(cx);
if (!argv.resize(cif->nargs)) {
JS_ReportOutOfMemory(cx);
return;
return false;
}
for (uint32_t i = 0; i < cif->nargs; ++i) {
@@ -6922,7 +6934,7 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
// the existing buffers.
RootedObject argType(cx, fninfo->mArgTypes[i]);
if (!ConvertToJS(cx, argType, nullptr, args[i], false, false, argv[i]))
return;
return false;
}
// Call the JS function. 'thisObj' may be nullptr, in which case the JS
@@ -6943,11 +6955,9 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
// Something failed. The callee may have thrown, or it may not have
// returned a value that ImplicitConvert() was happy with. Depending on how
// prudent the consumer has been, we may or may not have a recovery plan.
// In any case, a JS exception cannot be passed to C code, so report the
// exception if any and clear it from the cx.
if (JS_IsExceptionPending(cx))
JS_ReportPendingException(cx);
//
// Note that PrepareScriptEnvironmentAndInvoke should take care of reporting
// the exception.
if (cinfo->errResult) {
// Good case: we have a sentinel that we can return. Copy it in place of
@@ -6961,15 +6971,8 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
memcpy(result, cinfo->errResult, copySize);
} else {
// Bad case: not much we can do here. The rv is already zeroed out, so we
// just report (another) error and hope for the best. JS_ReportError will
// actually throw an exception here, so then we have to report it. Again.
// Ugh.
JS_ReportError(cx, "JavaScript callback failed, and an error sentinel "
"was not specified.");
if (JS_IsExceptionPending(cx))
JS_ReportPendingException(cx);
return;
// just return and hope for the best.
return false;
}
}
@@ -6992,6 +6995,8 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
default:
break;
}
return true;
}
/*******************************************************************************
+1 -3
View File
@@ -314,9 +314,7 @@ struct FunctionInfo
// Parameters necessary for invoking a JS function from a C closure.
struct ClosureInfo
{
JSContext* cx; // JSContext to use
JSRuntime* rt; // Used in the destructor, where cx might have already
// been GCed.
JSRuntime* rt;
JS::Heap<JSObject*> closureObj; // CClosure object
JS::Heap<JSObject*> typeObj; // FunctionType describing the C function
JS::Heap<JSObject*> thisObj; // 'this' object to use for the JS function call
+2 -2
View File
@@ -44,7 +44,7 @@ struct AutoFinishGC
class AutoTraceSession
{
public:
explicit AutoTraceSession(JSRuntime* rt, HeapState state = Tracing);
explicit AutoTraceSession(JSRuntime* rt, JS::HeapState state = JS::HeapState::Tracing);
~AutoTraceSession();
protected:
@@ -55,7 +55,7 @@ class AutoTraceSession
AutoTraceSession(const AutoTraceSession&) = delete;
void operator=(const AutoTraceSession&) = delete;
HeapState prevState;
JS::HeapState prevState;
};
struct AutoPrepareForTracing
+2 -9
View File
@@ -594,12 +594,6 @@ class GCRuntime
void setParameter(JSGCParamKey key, uint32_t value);
uint32_t getParameter(JSGCParamKey key, const AutoLockGC& lock);
bool isHeapBusy() { return heapState != js::Idle; }
bool isHeapMajorCollecting() { return heapState == js::MajorCollecting; }
bool isHeapMinorCollecting() { return heapState == js::MinorCollecting; }
bool isHeapCollecting() { return isHeapMajorCollecting() || isHeapMinorCollecting(); }
bool isHeapCompacting() { return isHeapMajorCollecting() && state() == COMPACT; }
bool triggerGC(JS::gcreason::Reason reason);
void maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock);
bool triggerZoneGC(Zone* zone, JS::gcreason::Reason reason);
@@ -666,7 +660,8 @@ class GCRuntime
public:
// Internal public interface
js::gc::State state() { return incrementalState; }
js::gc::State state() const { return incrementalState; }
bool isHeapCompacting() const { return state() == COMPACT; }
bool isBackgroundSweeping() { return helperState.isBackgroundSweeping(); }
void waitBackgroundSweepEnd() { helperState.waitBackgroundSweepEnd(); }
void waitBackgroundSweepOrAllocEnd() {
@@ -1209,8 +1204,6 @@ class GCRuntime
bool poked;
volatile js::HeapState heapState;
/*
* These options control the zealousness of the GC. The fundamental values
* are nextScheduled and gcDebugCompartmentGC. At every allocation,
+6 -22
View File
@@ -378,28 +378,13 @@ js::TenuringTracer::TenuringTracer(JSRuntime* rt, Nursery* nursery)
, tenuredSize(0)
, head(nullptr)
, tail(&head)
, savedRuntimeNeedBarrier(rt->needsIncrementalBarrier())
{
rt->gc.incGcNumber();
// We disable the runtime needsIncrementalBarrier() check so that
// pre-barriers do not fire on objects that have been relocated. The
// pre-barrier's call to obj->zone() will try to look through shape_,
// which is now the relocation magic and will crash. However,
// zone->needsIncrementalBarrier() must still be set correctly so that
// allocations we make in minor GCs between incremental slices will
// allocate their objects marked.
rt->setNeedsIncrementalBarrier(false);
}
js::TenuringTracer::~TenuringTracer()
{
runtime()->setNeedsIncrementalBarrier(savedRuntimeNeedBarrier);
}
#define TIME_START(name) int64_t timstampStart_##name = enableProfiling_ ? PRMJ_Now() : 0
#define TIME_END(name) int64_t timstampEnd_##name = enableProfiling_ ? PRMJ_Now() : 0
#define TIME_TOTAL(name) (timstampEnd_##name - timstampStart_##name)
#define TIME_START(name) int64_t timestampStart_##name = enableProfiling_ ? PRMJ_Now() : 0
#define TIME_END(name) int64_t timestampEnd_##name = enableProfiling_ ? PRMJ_Now() : 0
#define TIME_TOTAL(name) (timestampEnd_##name - timestampStart_##name)
void
js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList* pretenureGroups)
@@ -427,9 +412,9 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList
TraceMinorGCStart();
TIME_START(total);
int64_t timestampStart_total = PRMJ_Now();
AutoTraceSession session(rt, MinorCollecting);
AutoTraceSession session(rt, JS::HeapState::MinorCollecting);
AutoStopVerifyingBarriers av(rt, false);
AutoDisableProxyCheck disableStrictProxyChecking(rt);
mozilla::DebugOnly<AutoEnterOOMUnsafeRegion> oomUnsafeRegion;
@@ -554,11 +539,10 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList
if (rt->gc.usage.gcBytes() >= rt->gc.tunables.gcMaxBytes())
disable();
TIME_END(total);
int64_t totalTime = PRMJ_Now() - timestampStart_total;
TraceMinorGCEnd();
int64_t totalTime = TIME_TOTAL(total);
if (enableProfiling_ && totalTime >= profileThreshold_) {
static bool printedHeader = false;
if (!printedHeader) {
-4
View File
@@ -60,11 +60,7 @@ class TenuringTracer : public JSTracer
gc::RelocationOverlay* head;
gc::RelocationOverlay** tail;
// Save and restore all of the runtime state we use during MinorGC.
bool savedRuntimeNeedBarrier;
TenuringTracer(JSRuntime* rt, Nursery* nursery);
~TenuringTracer();
public:
const Nursery& nursery() const { return nursery_; }
+4 -4
View File
@@ -456,7 +456,7 @@ js::gc::GCRuntime::markRuntime(JSTracer* trc,
TraceRoot(trc, &vec[i].script, "scriptAndCountsVector");
}
if (!rt->isBeingDestroyed() && !trc->runtime()->isHeapMinorCollecting()) {
if (!rt->isBeingDestroyed() && !rt->isHeapMinorCollecting()) {
gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_RUNTIME_DATA);
if (traceOrMark == TraceRuntime || rt->atomsCompartment()->zone()->isCollecting()) {
@@ -475,7 +475,7 @@ js::gc::GCRuntime::markRuntime(JSTracer* trc,
continue;
/* Do not discard scripts with counts while profiling. */
if (rt->profilingScripts && !isHeapMinorCollecting()) {
if (rt->profilingScripts && !rt->isHeapMinorCollecting()) {
for (ZoneCellIterUnderGC i(zone, AllocKind::SCRIPT); !i.done(); i.next()) {
JSScript* script = i.get<JSScript>();
if (script->hasScriptCounts()) {
@@ -488,7 +488,7 @@ js::gc::GCRuntime::markRuntime(JSTracer* trc,
/* We can't use GCCompartmentsIter if we're called from TraceRuntime. */
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
if (trc->runtime()->isHeapMinorCollecting())
if (rt->isHeapMinorCollecting())
c->globalWriteBarriered = false;
if (traceOrMark == MarkRuntime && !c->zone()->isCollecting())
@@ -515,7 +515,7 @@ js::gc::GCRuntime::markRuntime(JSTracer* trc,
jit::MarkJitActivations(rt, trc);
if (!isHeapMinorCollecting()) {
if (!rt->isHeapMinorCollecting()) {
gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_EMBEDDING);
/*
-2
View File
@@ -231,7 +231,6 @@ gc::GCRuntime::startVerifyPreBarriers()
incrementalState = MARK;
marker.start();
rt->setNeedsIncrementalBarrier(true);
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
PurgeJITCaches(zone);
zone->setNeedsIncrementalBarrier(true, Zone::UpdateJit);
@@ -328,7 +327,6 @@ gc::GCRuntime::endVerifyPreBarriers()
zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit);
PurgeJITCaches(zone);
}
rt->setNeedsIncrementalBarrier(false);
/*
* We need to bump gcNumber so that the methodjit knows that jitcode has
+3 -3
View File
@@ -133,8 +133,8 @@ struct Zone : public JS::shadow::Zone,
bool isTooMuchMalloc() const { return gcMallocBytes <= 0; }
void onTooMuchMalloc();
void* onOutOfMemory(void* p, size_t nbytes) {
return runtimeFromMainThread()->onOutOfMemory(p, nbytes);
void* onOutOfMemory(js::AllocFunction allocFunc, size_t nbytes, void* reallocPtr = nullptr) {
return runtimeFromMainThread()->onOutOfMemory(allocFunc, nbytes, reallocPtr);
}
void reportAllocationOverflow() { js::ReportAllocationOverflow(nullptr); }
@@ -187,7 +187,7 @@ struct Zone : public JS::shadow::Zone,
// tracer.
bool requireGCTracer() const {
JSRuntime* rt = runtimeFromAnyThread();
return rt->isHeapMajorCollecting() && !rt->isHeapCompacting() && gcState_ != NoGC;
return rt->isHeapMajorCollecting() && !rt->gc.isHeapCompacting() && gcState_ != NoGC;
}
bool isGCMarking() {
@@ -0,0 +1,13 @@
// |jit-test| baseline-eager; error: TypeError
try {
__defineGetter__("x", Iterator)()
} catch (e) {}
f = function() {
return (function() {
this.x
})
}()
try {
f()
} catch (e) {}
f()
@@ -0,0 +1,20 @@
function f() {
var propNames = ["a","b","c","d","e","f","g","h","i","j","x","y"];
var arr = [];
for (var i=0; i<64; i++)
arr.push({x:1, y:2});
for (var i=0; i<64; i++) {
// Make sure there are expandos with dynamic slots for each object.
for (var j = 0; j < propNames.length; j++)
arr[i][propNames[j]] = j;
}
var res = 0;
for (var i=0; i<100000; i++) {
var o = arr[i % 64];
var p = propNames[i % propNames.length];
res += o[p];
}
assertEq(res, 549984);
}
f();
+4 -2
View File
@@ -679,8 +679,10 @@ RecompileBaselineScriptForDebugMode(JSContext* cx, JSScript* script,
_(Call_ScriptedApplyArray) \
_(Call_ScriptedApplyArguments) \
_(Call_ScriptedFunCall) \
_(GetElem_NativePrototypeCallNative) \
_(GetElem_NativePrototypeCallScripted) \
_(GetElem_NativePrototypeCallNativeName) \
_(GetElem_NativePrototypeCallNativeSymbol) \
_(GetElem_NativePrototypeCallScriptedName) \
_(GetElem_NativePrototypeCallScriptedSymbol) \
_(GetProp_CallScripted) \
_(GetProp_CallNative) \
_(GetProp_CallDOMProxyNative) \
+601 -312
View File
File diff suppressed because it is too large Load Diff
+201 -97
View File
@@ -1527,11 +1527,10 @@ class ICGetElem_Fallback : public ICMonitoredFallbackStub
class ICGetElemNativeStub : public ICMonitoredStub
{
public:
enum AccessType { FixedSlot = 0, DynamicSlot, NativeGetter, ScriptedGetter };
enum AccessType { FixedSlot = 0, DynamicSlot, UnboxedProperty, NativeGetter, ScriptedGetter };
protected:
HeapPtrShape shape_;
HeapPtrPropertyName name_;
HeapReceiverGuard receiverGuard_;
static const unsigned NEEDS_ATOMIZE_SHIFT = 0;
static const uint16_t NEEDS_ATOMIZE_MASK = 0x1;
@@ -1539,25 +1538,20 @@ class ICGetElemNativeStub : public ICMonitoredStub
static const unsigned ACCESSTYPE_SHIFT = 1;
static const uint16_t ACCESSTYPE_MASK = 0x3;
static const unsigned ISSYMBOL_SHIFT = 3;
static const uint16_t ISSYMBOL_MASK = 0x1;
ICGetElemNativeStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
Shape* shape, PropertyName* name, AccessType acctype,
bool needsAtomize);
ReceiverGuard guard, AccessType acctype, bool needsAtomize, bool isSymbol);
~ICGetElemNativeStub();
public:
HeapPtrShape& shape() {
return shape_;
HeapReceiverGuard& receiverGuard() {
return receiverGuard_;
}
static size_t offsetOfShape() {
return offsetof(ICGetElemNativeStub, shape_);
}
HeapPtrPropertyName& name() {
return name_;
}
static size_t offsetOfName() {
return offsetof(ICGetElemNativeStub, name_);
static size_t offsetOfReceiverGuard() {
return offsetof(ICGetElemNativeStub, receiverGuard_);
}
AccessType accessType() const {
@@ -1567,21 +1561,56 @@ class ICGetElemNativeStub : public ICMonitoredStub
bool needsAtomize() const {
return (extra_ >> NEEDS_ATOMIZE_SHIFT) & NEEDS_ATOMIZE_MASK;
}
bool isSymbol() const {
return (extra_ >> ISSYMBOL_SHIFT) & ISSYMBOL_MASK;
}
};
class ICGetElemNativeSlotStub : public ICGetElemNativeStub
template <class T>
class ICGetElemNativeStubImpl : public ICGetElemNativeStub
{
protected:
HeapPtr<T> key_;
ICGetElemNativeStubImpl(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
ReceiverGuard guard, const T* key, AccessType acctype, bool needsAtomize)
: ICGetElemNativeStub(kind, stubCode, firstMonitorStub, guard, acctype, needsAtomize,
mozilla::IsSame<T, JS::Symbol*>::value),
key_(*key)
{}
public:
HeapPtr<T>& key() {
return key_;
}
static size_t offsetOfKey() {
return offsetof(ICGetElemNativeStubImpl, key_);
}
};
typedef ICGetElemNativeStub::AccessType AccType;
template <class T>
class ICGetElemNativeSlotStub : public ICGetElemNativeStubImpl<T>
{
protected:
uint32_t offset_;
ICGetElemNativeSlotStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
Shape* shape, PropertyName* name,
AccessType acctype, bool needsAtomize, uint32_t offset)
: ICGetElemNativeStub(kind, stubCode, firstMonitorStub, shape, name, acctype, needsAtomize),
ReceiverGuard guard, const T* key, AccType acctype, bool needsAtomize,
uint32_t offset)
: ICGetElemNativeStubImpl<T>(kind, stubCode, firstMonitorStub, guard, key, acctype, needsAtomize),
offset_(offset)
{
MOZ_ASSERT(kind == GetElem_NativeSlot || kind == GetElem_NativePrototypeSlot);
MOZ_ASSERT(acctype == FixedSlot || acctype == DynamicSlot);
MOZ_ASSERT(kind == ICStub::GetElem_NativeSlotName ||
kind == ICStub::GetElem_NativeSlotSymbol ||
kind == ICStub::GetElem_NativePrototypeSlotName ||
kind == ICStub::GetElem_NativePrototypeSlotSymbol ||
kind == ICStub::GetElem_UnboxedPropertyName);
MOZ_ASSERT(acctype == ICGetElemNativeStub::FixedSlot ||
acctype == ICGetElemNativeStub::DynamicSlot ||
acctype == ICGetElemNativeStub::UnboxedProperty);
}
public:
@@ -1594,15 +1623,16 @@ class ICGetElemNativeSlotStub : public ICGetElemNativeStub
}
};
class ICGetElemNativeGetterStub : public ICGetElemNativeStub
template <class T>
class ICGetElemNativeGetterStub : public ICGetElemNativeStubImpl<T>
{
protected:
HeapPtrFunction getter_;
uint32_t pcOffset_;
ICGetElemNativeGetterStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
Shape* shape, PropertyName* name, AccessType acctype,
bool needsAtomize, JSFunction* getter, uint32_t pcOffset);
ReceiverGuard guard, const T* key, AccType acctype, bool needsAtomize,
JSFunction* getter, uint32_t pcOffset);
public:
HeapPtrFunction& getter() {
@@ -1617,26 +1647,61 @@ class ICGetElemNativeGetterStub : public ICGetElemNativeStub
}
};
class ICGetElem_NativeSlot : public ICGetElemNativeSlotStub
template <class T>
ICStub::Kind
getGetElemStubKind(ICStub::Kind kind)
{
MOZ_ASSERT(kind == ICStub::GetElem_NativeSlotName ||
kind == ICStub::GetElem_NativePrototypeSlotName ||
kind == ICStub::GetElem_NativePrototypeCallNativeName ||
kind == ICStub::GetElem_NativePrototypeCallScriptedName);
return static_cast<ICStub::Kind>(kind + mozilla::IsSame<T, JS::Symbol*>::value);
}
template <class T>
class ICGetElem_NativeSlot : public ICGetElemNativeSlotStub<T>
{
friend class ICStubSpace;
ICGetElem_NativeSlot(JitCode* stubCode, ICStub* firstMonitorStub,
Shape* shape, PropertyName* name,
AccessType acctype, bool needsAtomize, uint32_t offset)
: ICGetElemNativeSlotStub(ICStub::GetElem_NativeSlot, stubCode, firstMonitorStub, shape,
name, acctype, needsAtomize, offset)
ICGetElem_NativeSlot(JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard,
const T* key, AccType acctype, bool needsAtomize, uint32_t offset)
: ICGetElemNativeSlotStub<T>(getGetElemStubKind<T>(ICStub::GetElem_NativeSlotName),
stubCode, firstMonitorStub, guard,
key, acctype, needsAtomize, offset)
{}
};
class ICGetElem_NativePrototypeSlot : public ICGetElemNativeSlotStub
class ICGetElem_NativeSlotName :
public ICGetElem_NativeSlot<PropertyName*>
{};
class ICGetElem_NativeSlotSymbol :
public ICGetElem_NativeSlot<JS::Symbol*>
{};
template <class T>
class ICGetElem_UnboxedProperty : public ICGetElemNativeSlotStub<T>
{
friend class ICStubSpace;
ICGetElem_UnboxedProperty(JitCode* stubCode, ICStub* firstMonitorStub,
ReceiverGuard guard, const T* key, AccType acctype,
bool needsAtomize, uint32_t offset)
: ICGetElemNativeSlotStub<T>(ICStub::GetElem_UnboxedPropertyName, stubCode, firstMonitorStub,
guard, key, acctype, needsAtomize, offset)
{}
};
class ICGetElem_UnboxedPropertyName :
public ICGetElem_UnboxedProperty<PropertyName*>
{};
template <class T>
class ICGetElem_NativePrototypeSlot : public ICGetElemNativeSlotStub<T>
{
friend class ICStubSpace;
HeapPtrObject holder_;
HeapPtrShape holderShape_;
ICGetElem_NativePrototypeSlot(JitCode* stubCode, ICStub* firstMonitorStub,
Shape* shape, PropertyName* name,
AccessType acctype, bool needsAtomize, uint32_t offset,
ICGetElem_NativePrototypeSlot(JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard,
const T* key, AccType acctype, bool needsAtomize, uint32_t offset,
JSObject* holder, Shape* holderShape);
public:
@@ -1655,7 +1720,15 @@ class ICGetElem_NativePrototypeSlot : public ICGetElemNativeSlotStub
}
};
class ICGetElemNativePrototypeCallStub : public ICGetElemNativeGetterStub
class ICGetElem_NativePrototypeSlotName :
public ICGetElem_NativePrototypeSlot<PropertyName*>
{};
class ICGetElem_NativePrototypeSlotSymbol :
public ICGetElem_NativePrototypeSlot<JS::Symbol*>
{};
template <class T>
class ICGetElemNativePrototypeCallStub : public ICGetElemNativeGetterStub<T>
{
friend class ICStubSpace;
HeapPtrObject holder_;
@@ -1663,10 +1736,9 @@ class ICGetElemNativePrototypeCallStub : public ICGetElemNativeGetterStub
protected:
ICGetElemNativePrototypeCallStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
Shape* shape, PropertyName* name,
AccessType acctype, bool needsAtomize, JSFunction* getter,
uint32_t pcOffset, JSObject* holder,
Shape* holderShape);
ReceiverGuard guard, const T* key, AccType acctype,
bool needsAtomize, JSFunction* getter, uint32_t pcOffset,
JSObject* holder, Shape* holderShape);
public:
HeapPtrObject& holder() {
@@ -1684,146 +1756,178 @@ class ICGetElemNativePrototypeCallStub : public ICGetElemNativeGetterStub
}
};
class ICGetElem_NativePrototypeCallNative : public ICGetElemNativePrototypeCallStub
template <class T>
class ICGetElem_NativePrototypeCallNative : public ICGetElemNativePrototypeCallStub<T>
{
friend class ICStubSpace;
ICGetElem_NativePrototypeCallNative(JitCode* stubCode, ICStub* firstMonitorStub,
Shape* shape, PropertyName* name,
AccessType acctype, bool needsAtomize,
JSFunction* getter, uint32_t pcOffset,
ReceiverGuard guard, const T* key, AccType acctype,
bool needsAtomize, JSFunction* getter, uint32_t pcOffset,
JSObject* holder, Shape* holderShape)
: ICGetElemNativePrototypeCallStub(GetElem_NativePrototypeCallNative,
stubCode, firstMonitorStub, shape, name,
acctype, needsAtomize, getter, pcOffset, holder,
holderShape)
: ICGetElemNativePrototypeCallStub<T>(getGetElemStubKind<T>(
ICStub::GetElem_NativePrototypeCallNativeName),
stubCode, firstMonitorStub, guard, key,
acctype, needsAtomize, getter, pcOffset, holder,
holderShape)
{}
public:
static ICGetElem_NativePrototypeCallNative* Clone(JSContext* cx, ICStubSpace* space,
ICStub* firstMonitorStub,
ICGetElem_NativePrototypeCallNative& other);
static ICGetElem_NativePrototypeCallNative<T>* Clone(JSContext* cx, ICStubSpace* space,
ICStub* firstMonitorStub,
ICGetElem_NativePrototypeCallNative<T>& other);
};
class ICGetElem_NativePrototypeCallScripted : public ICGetElemNativePrototypeCallStub
class ICGetElem_NativePrototypeCallNativeName :
public ICGetElem_NativePrototypeCallNative<PropertyName*>
{};
class ICGetElem_NativePrototypeCallNativeSymbol :
public ICGetElem_NativePrototypeCallNative<JS::Symbol*>
{};
template <class T>
class ICGetElem_NativePrototypeCallScripted : public ICGetElemNativePrototypeCallStub<T>
{
friend class ICStubSpace;
ICGetElem_NativePrototypeCallScripted(JitCode* stubCode, ICStub* firstMonitorStub,
Shape* shape, PropertyName* name,
AccessType acctype, bool needsAtomize,
JSFunction* getter, uint32_t pcOffset,
ReceiverGuard guard, const T* key, AccType acctype,
bool needsAtomize, JSFunction* getter, uint32_t pcOffset,
JSObject* holder, Shape* holderShape)
: ICGetElemNativePrototypeCallStub(GetElem_NativePrototypeCallScripted,
stubCode, firstMonitorStub, shape, name,
acctype, needsAtomize, getter, pcOffset, holder,
holderShape)
: ICGetElemNativePrototypeCallStub<T>(getGetElemStubKind<T>(
ICStub::GetElem_NativePrototypeCallScriptedName),
stubCode, firstMonitorStub, guard, key, acctype,
needsAtomize, getter, pcOffset, holder, holderShape)
{}
public:
static ICGetElem_NativePrototypeCallScripted*
static ICGetElem_NativePrototypeCallScripted<T>*
Clone(JSContext* cx, ICStubSpace* space,
ICStub* firstMonitorStub,
ICGetElem_NativePrototypeCallScripted& other);
ICGetElem_NativePrototypeCallScripted<T>& other);
};
class ICGetElem_NativePrototypeCallScriptedName :
public ICGetElem_NativePrototypeCallScripted<PropertyName*>
{};
class ICGetElem_NativePrototypeCallScriptedSymbol :
public ICGetElem_NativePrototypeCallScripted<JS::Symbol*>
{};
// Compiler for GetElem_NativeSlot and GetElem_NativePrototypeSlot stubs.
template <class T>
class ICGetElemNativeCompiler : public ICStubCompiler
{
bool isCallElem_;
ICStub* firstMonitorStub_;
HandleObject obj_;
HandleObject holder_;
HandlePropertyName name_;
ICGetElemNativeStub::AccessType acctype_;
Handle<T> key_;
AccType acctype_;
bool needsAtomize_;
uint32_t offset_;
JSValueType unboxedType_;
HandleFunction getter_;
uint32_t pcOffset_;
bool emitCheckKey(MacroAssembler& masm, Label& failure);
bool emitCallNative(MacroAssembler& masm, Register objReg);
bool emitCallScripted(MacroAssembler& masm, Register objReg);
bool generateStubCode(MacroAssembler& masm);
protected:
virtual int32_t getKey() const {
MOZ_ASSERT(static_cast<int32_t>(acctype_) <= 7);
MOZ_ASSERT(static_cast<int32_t>(unboxedType_) <= 8);
return static_cast<int32_t>(engine_) |
(static_cast<int32_t>(kind) << 1) |
#if JS_HAS_NO_SUCH_METHOD
return static_cast<int32_t>(engine_) |
(static_cast<int32_t>(kind) << 1) |
(static_cast<int32_t>(isCallElem_) << 17) |
(static_cast<int32_t>(needsAtomize_) << 18) |
(static_cast<int32_t>(acctype_) << 19);
#else
return static_cast<int32_t>(engine_) |
(static_cast<int32_t>(kind) << 1) |
(static_cast<int32_t>(needsAtomize_) << 17) |
(static_cast<int32_t>(acctype_) << 18);
#endif
(static_cast<int32_t>(needsAtomize_) << 18) |
(static_cast<int32_t>(acctype_) << 19) |
(static_cast<int32_t>(unboxedType_) << 22) |
(static_cast<int32_t>(mozilla::IsSame<JS::Symbol*, T>::value) << 26) |
(HeapReceiverGuard::keyBits(obj_) << 27);
}
public:
ICGetElemNativeCompiler(JSContext* cx, ICStub::Kind kind, bool isCallElem,
ICStub* firstMonitorStub, HandleObject obj, HandleObject holder,
HandlePropertyName name, ICGetElemNativeStub::AccessType acctype,
bool needsAtomize, uint32_t offset)
Handle<T> key, AccType acctype, bool needsAtomize, uint32_t offset,
JSValueType unboxedType = JSVAL_TYPE_MAGIC)
: ICStubCompiler(cx, kind, Engine::Baseline),
isCallElem_(isCallElem),
firstMonitorStub_(firstMonitorStub),
obj_(obj),
holder_(holder),
name_(name),
key_(key),
acctype_(acctype),
needsAtomize_(needsAtomize),
offset_(offset),
unboxedType_(unboxedType),
getter_(nullptr),
pcOffset_(0)
{}
ICGetElemNativeCompiler(JSContext* cx, ICStub::Kind kind, ICStub* firstMonitorStub,
HandleObject obj, HandleObject holder, HandlePropertyName name,
ICGetElemNativeStub::AccessType acctype, bool needsAtomize,
HandleFunction getter, uint32_t pcOffset, bool isCallElem)
HandleObject obj, HandleObject holder, Handle<T> key, AccType acctype,
bool needsAtomize, HandleFunction getter, uint32_t pcOffset,
bool isCallElem)
: ICStubCompiler(cx, kind, Engine::Baseline),
isCallElem_(false),
firstMonitorStub_(firstMonitorStub),
obj_(obj),
holder_(holder),
name_(name),
key_(key),
acctype_(acctype),
needsAtomize_(needsAtomize),
offset_(0),
unboxedType_(JSVAL_TYPE_MAGIC),
getter_(getter),
pcOffset_(pcOffset)
{}
ICStub* getStub(ICStubSpace* space) {
RootedShape shape(cx, obj_->as<NativeObject>().lastProperty());
if (kind == ICStub::GetElem_NativeSlot) {
RootedReceiverGuard guard(cx, ReceiverGuard(obj_));
if (kind == ICStub::GetElem_NativeSlotName || kind == ICStub::GetElem_NativeSlotSymbol) {
MOZ_ASSERT(obj_ == holder_);
return newStub<ICGetElem_NativeSlot>(
space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_,
offset_);
return newStub<ICGetElem_NativeSlot<T>>(
space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
needsAtomize_, offset_);
}
if (kind == ICStub::GetElem_UnboxedPropertyName) {
MOZ_ASSERT(obj_ == holder_);
return newStub<ICGetElem_UnboxedProperty<T>>(
space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
needsAtomize_, offset_);
}
MOZ_ASSERT(obj_ != holder_);
RootedShape holderShape(cx, holder_->as<NativeObject>().lastProperty());
if (kind == ICStub::GetElem_NativePrototypeSlot) {
return newStub<ICGetElem_NativePrototypeSlot>(
space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_,
offset_, holder_, holderShape);
if (kind == ICStub::GetElem_NativePrototypeSlotName ||
kind == ICStub::GetElem_NativePrototypeSlotSymbol)
{
return newStub<ICGetElem_NativePrototypeSlot<T>>(
space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
needsAtomize_, offset_, holder_, holderShape);
}
if (kind == ICStub::GetElem_NativePrototypeCallNative) {
return newStub<ICGetElem_NativePrototypeCallNative>(
space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_,
getter_, pcOffset_, holder_, holderShape);
if (kind == ICStub::GetElem_NativePrototypeCallNativeSymbol ||
kind == ICStub::GetElem_NativePrototypeCallNativeName) {
return newStub<ICGetElem_NativePrototypeCallNative<T>>(
space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
needsAtomize_, getter_, pcOffset_, holder_, holderShape);
}
MOZ_ASSERT(kind == ICStub::GetElem_NativePrototypeCallScripted);
if (kind == ICStub::GetElem_NativePrototypeCallScripted) {
return newStub<ICGetElem_NativePrototypeCallScripted>(
space, getStubCode(), firstMonitorStub_, shape, name_, acctype_, needsAtomize_,
getter_, pcOffset_, holder_, holderShape);
MOZ_ASSERT(kind == ICStub::GetElem_NativePrototypeCallScriptedName ||
kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol);
if (kind == ICStub::GetElem_NativePrototypeCallScriptedName ||
kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol) {
return newStub<ICGetElem_NativePrototypeCallScripted<T>>(
space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_,
needsAtomize_, getter_, pcOffset_, holder_, holderShape);
}
MOZ_CRASH("Invalid kind.");
+9 -4
View File
@@ -73,10 +73,15 @@ namespace jit {
_(Call_IsSuspendedStarGenerator) \
\
_(GetElem_Fallback) \
_(GetElem_NativeSlot) \
_(GetElem_NativePrototypeSlot) \
_(GetElem_NativePrototypeCallNative) \
_(GetElem_NativePrototypeCallScripted) \
_(GetElem_NativeSlotName) \
_(GetElem_NativeSlotSymbol) \
_(GetElem_NativePrototypeSlotName) \
_(GetElem_NativePrototypeSlotSymbol) \
_(GetElem_NativePrototypeCallNativeName) \
_(GetElem_NativePrototypeCallNativeSymbol) \
_(GetElem_NativePrototypeCallScriptedName) \
_(GetElem_NativePrototypeCallScriptedSymbol) \
_(GetElem_UnboxedPropertyName) \
_(GetElem_String) \
_(GetElem_Dense) \
_(GetElem_UnboxedArray) \
+9 -4
View File
@@ -744,10 +744,15 @@ BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc)
case ICStub::GetProp_CallDOMProxyNative:
case ICStub::GetProp_CallDOMProxyWithGenerationNative:
case ICStub::GetProp_DOMProxyShadowed:
case ICStub::GetElem_NativeSlot:
case ICStub::GetElem_NativePrototypeSlot:
case ICStub::GetElem_NativePrototypeCallNative:
case ICStub::GetElem_NativePrototypeCallScripted:
case ICStub::GetElem_NativeSlotName:
case ICStub::GetElem_NativeSlotSymbol:
case ICStub::GetElem_NativePrototypeSlotName:
case ICStub::GetElem_NativePrototypeSlotSymbol:
case ICStub::GetElem_NativePrototypeCallNativeName:
case ICStub::GetElem_NativePrototypeCallNativeSymbol:
case ICStub::GetElem_NativePrototypeCallScriptedName:
case ICStub::GetElem_NativePrototypeCallScriptedSymbol:
case ICStub::GetElem_UnboxedPropertyName:
case ICStub::GetElem_String:
case ICStub::GetElem_Dense:
case ICStub::GetElem_TypedArray:
+45 -15
View File
@@ -860,18 +860,24 @@ static void
GenerateReadUnboxed(JSContext* cx, IonScript* ion, MacroAssembler& masm,
IonCache::StubAttacher& attacher, JSObject* obj,
const UnboxedLayout::Property* property,
Register object, TypedOrValueRegister output)
Register object, TypedOrValueRegister output,
Label* failures = nullptr)
{
// Guard on the type of the object.
attacher.branchNextStub(masm, Assembler::NotEqual,
Address(object, JSObject::offsetOfGroup()),
ImmGCPtr(obj->group()));
// Guard on the group of the object.
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
Address(object, JSObject::offsetOfGroup()),
ImmGCPtr(obj->group()), failures);
Address address(object, UnboxedPlainObject::offsetOfData() + property->offset);
masm.loadUnboxedProperty(address, property->type, output);
attacher.jumpRejoin(masm);
if (failures) {
masm.bind(failures);
attacher.jumpNextStub(masm);
}
}
static bool
@@ -3313,7 +3319,7 @@ const size_t GetElementIC::MAX_FAILED_UPDATES = 16;
GetElementIC::canAttachGetProp(JSObject* obj, const Value& idval, jsid id)
{
uint32_t dummy;
return obj->isNative() &&
return (obj->isNative() || obj->is<UnboxedPlainObject>()) &&
idval.isString() &&
JSID_IS_ATOM(id) &&
!JSID_TO_ATOM(id)->isIndex(&dummy);
@@ -3339,18 +3345,39 @@ GetElementIC::attachGetProp(JSContext* cx, HandleScript outerScript, IonScript*
{
MOZ_ASSERT(index().reg().hasValue());
RootedNativeObject holder(cx);
RootedNativeObject baseHolder(cx);
RootedShape shape(cx);
GetPropertyIC::NativeGetPropCacheability canCache =
CanAttachNativeGetProp(cx, *this, obj, name, &holder, &shape,
CanAttachNativeGetProp(cx, *this, obj, name, &baseHolder, &shape,
/* skipArrayLen =*/true);
bool cacheable = canCache == GetPropertyIC::CanAttachReadSlot ||
(canCache == GetPropertyIC::CanAttachCallGetter &&
output().hasValue());
RootedObject holder(cx, baseHolder);
if (!cacheable) {
if (canCache == GetPropertyIC::CanAttachReadSlot) {
// OK to attach.
} else if (canCache == GetPropertyIC::CanAttachCallGetter) {
if (!output().hasValue()) {
JitSpew(JitSpew_IonIC, "GETELEM uncacheable property");
return true;
}
} else if (obj->is<UnboxedPlainObject>()) {
MOZ_ASSERT(canCache == GetPropertyIC::CanAttachNone);
const UnboxedLayout::Property* property =
obj->as<UnboxedPlainObject>().layout().lookup(name);
if (property) {
// OK to attach.
} else {
UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando();
shape = expando ? expando->lookup(cx, name) : nullptr;
if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot()) {
JitSpew(JitSpew_IonIC, "GETELEM uncacheable property");
return true;
}
canCache = GetPropertyIC::CanAttachReadSlot;
holder = obj;
}
} else {
JitSpew(JitSpew_IonIC, "GETELEM uncacheable property");
return true;
}
@@ -3413,9 +3440,7 @@ GetElementIC::attachGetProp(JSContext* cx, HandleScript outerScript, IonScript*
if (canCache == GetPropertyIC::CanAttachReadSlot) {
GenerateReadSlot(cx, ion, masm, attacher, obj, holder, shape, object(), output(),
&failures);
} else {
MOZ_ASSERT(canCache == GetPropertyIC::CanAttachCallGetter);
} else if (canCache == GetPropertyIC::CanAttachCallGetter) {
// Set the frame for bailout safety of the OOL call.
void* returnAddr = GetReturnAddressToIonCode(cx);
if (!GenerateCallGetter(cx, ion, masm, attacher, obj, name, holder, shape, liveRegs_,
@@ -3423,6 +3448,11 @@ GetElementIC::attachGetProp(JSContext* cx, HandleScript outerScript, IonScript*
{
return false;
}
} else {
MOZ_ASSERT(canCache == GetPropertyIC::CanAttachNone);
GenerateReadUnboxed(cx, ion, masm, attacher, obj,
obj->as<UnboxedPlainObject>().layout().lookup(name),
object(), output(), &failures);
}
return linkAndAttachStub(cx, masm, attacher, ion, "property");
+9 -1
View File
@@ -738,6 +738,14 @@ JitcodeGlobalTable::verifySkiplist()
}
#endif // DEBUG
void
JitcodeGlobalTable::setAllEntriesAsExpired(JSRuntime* rt)
{
AutoSuppressProfilerSampling suppressSampling(rt);
for (Range r(*this); !r.empty(); r.popFront())
r.front()->setAsExpired();
}
bool
JitcodeGlobalTable::markIteratively(JSTracer* trc)
{
@@ -782,7 +790,7 @@ JitcodeGlobalTable::markIteratively(JSTracer* trc)
// types used by optimizations and scripts used for pc to line number
// mapping, alive as well.
if (!entry->isSampled(gen, lapCount)) {
entry->setGeneration(UINT32_MAX);
entry->setAsExpired();
if (!entry->baseEntry().isJitcodeMarkedFromAnyThread())
continue;
}
+4
View File
@@ -613,6 +613,9 @@ class JitcodeGlobalEntry
void setGeneration(uint32_t gen) {
baseEntry().setGeneration(gen);
}
void setAsExpired() {
baseEntry().setGeneration(UINT32_MAX);
}
bool isSampled(uint32_t currentGen, uint32_t lapCount) {
return baseEntry().isSampled(currentGen, lapCount);
}
@@ -984,6 +987,7 @@ class JitcodeGlobalTable
void removeEntry(JitcodeGlobalEntry& entry, JitcodeGlobalEntry** prevTower, JSRuntime* rt);
void releaseEntry(JitcodeGlobalEntry& entry, JitcodeGlobalEntry** prevTower, JSRuntime* rt);
void setAllEntriesAsExpired(JSRuntime* rt);
bool markIteratively(JSTracer* trc);
void sweep(JSRuntime* rt);
+51 -19
View File
@@ -189,29 +189,61 @@ ICStub::trace(JSTracer* trc)
TraceEdge(trc, &callStub->expectedThis(), "baseline-callstringsplit-this");
break;
}
case ICStub::GetElem_NativeSlot: {
ICGetElem_NativeSlot* getElemStub = toGetElem_NativeSlot();
TraceEdge(trc, &getElemStub->shape(), "baseline-getelem-native-shape");
TraceEdge(trc, &getElemStub->name(), "baseline-getelem-native-name");
case ICStub::GetElem_NativeSlotName:
case ICStub::GetElem_NativeSlotSymbol:
case ICStub::GetElem_UnboxedPropertyName: {
ICGetElemNativeStub* getElemStub = static_cast<ICGetElemNativeStub*>(this);
getElemStub->receiverGuard().trace(trc);
if (getElemStub->isSymbol()) {
ICGetElem_NativeSlot<JS::Symbol*>* typedGetElemStub = toGetElem_NativeSlotSymbol();
TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-native-key");
} else {
ICGetElemNativeSlotStub<PropertyName*>* typedGetElemStub =
reinterpret_cast<ICGetElemNativeSlotStub<PropertyName*>*>(this);
TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-native-key");
}
break;
}
case ICStub::GetElem_NativePrototypeSlot: {
ICGetElem_NativePrototypeSlot* getElemStub = toGetElem_NativePrototypeSlot();
TraceEdge(trc, &getElemStub->shape(), "baseline-getelem-nativeproto-shape");
TraceEdge(trc, &getElemStub->name(), "baseline-getelem-nativeproto-name");
TraceEdge(trc, &getElemStub->holder(), "baseline-getelem-nativeproto-holder");
TraceEdge(trc, &getElemStub->holderShape(), "baseline-getelem-nativeproto-holdershape");
case ICStub::GetElem_NativePrototypeSlotName:
case ICStub::GetElem_NativePrototypeSlotSymbol: {
ICGetElemNativeStub* getElemStub = static_cast<ICGetElemNativeStub*>(this);
getElemStub->receiverGuard().trace(trc);
if (getElemStub->isSymbol()) {
ICGetElem_NativePrototypeSlot<JS::Symbol*>* typedGetElemStub
= toGetElem_NativePrototypeSlotSymbol();
TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-nativeproto-key");
TraceEdge(trc, &typedGetElemStub->holder(), "baseline-getelem-nativeproto-holder");
TraceEdge(trc, &typedGetElemStub->holderShape(), "baseline-getelem-nativeproto-holdershape");
} else {
ICGetElem_NativePrototypeSlot<PropertyName*>* typedGetElemStub
= toGetElem_NativePrototypeSlotName();
TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-nativeproto-key");
TraceEdge(trc, &typedGetElemStub->holder(), "baseline-getelem-nativeproto-holder");
TraceEdge(trc, &typedGetElemStub->holderShape(), "baseline-getelem-nativeproto-holdershape");
}
break;
}
case ICStub::GetElem_NativePrototypeCallNative:
case ICStub::GetElem_NativePrototypeCallScripted: {
ICGetElemNativePrototypeCallStub* callStub =
reinterpret_cast<ICGetElemNativePrototypeCallStub*>(this);
TraceEdge(trc, &callStub->shape(), "baseline-getelem-nativeprotocall-shape");
TraceEdge(trc, &callStub->name(), "baseline-getelem-nativeprotocall-name");
TraceEdge(trc, &callStub->getter(), "baseline-getelem-nativeprotocall-getter");
TraceEdge(trc, &callStub->holder(), "baseline-getelem-nativeprotocall-holder");
TraceEdge(trc, &callStub->holderShape(), "baseline-getelem-nativeprotocall-holdershape");
case ICStub::GetElem_NativePrototypeCallNativeName:
case ICStub::GetElem_NativePrototypeCallNativeSymbol:
case ICStub::GetElem_NativePrototypeCallScriptedName:
case ICStub::GetElem_NativePrototypeCallScriptedSymbol: {
ICGetElemNativeStub* getElemStub = static_cast<ICGetElemNativeStub*>(this);
getElemStub->receiverGuard().trace(trc);
if (getElemStub->isSymbol()) {
ICGetElemNativePrototypeCallStub<JS::Symbol*>* callStub =
reinterpret_cast<ICGetElemNativePrototypeCallStub<JS::Symbol*>*>(this);
TraceEdge(trc, &callStub->key(), "baseline-getelem-nativeprotocall-key");
TraceEdge(trc, &callStub->getter(), "baseline-getelem-nativeprotocall-getter");
TraceEdge(trc, &callStub->holder(), "baseline-getelem-nativeprotocall-holder");
TraceEdge(trc, &callStub->holderShape(), "baseline-getelem-nativeprotocall-holdershape");
} else {
ICGetElemNativePrototypeCallStub<PropertyName*>* callStub =
reinterpret_cast<ICGetElemNativePrototypeCallStub<PropertyName*>*>(this);
TraceEdge(trc, &callStub->key(), "baseline-getelem-nativeprotocall-key");
TraceEdge(trc, &callStub->getter(), "baseline-getelem-nativeprotocall-getter");
TraceEdge(trc, &callStub->holder(), "baseline-getelem-nativeprotocall-holder");
TraceEdge(trc, &callStub->holderShape(), "baseline-getelem-nativeprotocall-holdershape");
}
break;
}
case ICStub::GetElem_Dense: {
+9 -4
View File
@@ -689,10 +689,15 @@ class ICStub
case Call_ScriptedFunCall:
case Call_StringSplit:
case WarmUpCounter_Fallback:
case GetElem_NativeSlot:
case GetElem_NativePrototypeSlot:
case GetElem_NativePrototypeCallNative:
case GetElem_NativePrototypeCallScripted:
case GetElem_NativeSlotName:
case GetElem_NativeSlotSymbol:
case GetElem_NativePrototypeSlotName:
case GetElem_NativePrototypeSlotSymbol:
case GetElem_NativePrototypeCallNativeName:
case GetElem_NativePrototypeCallNativeSymbol:
case GetElem_NativePrototypeCallScriptedName:
case GetElem_NativePrototypeCallScriptedSymbol:
case GetElem_UnboxedPropertyName:
case GetProp_CallScripted:
case GetProp_CallNative:
case GetProp_CallDOMProxyNative:
+2 -2
View File
@@ -11,9 +11,9 @@
using namespace js;
void*
TempAllocPolicy::onOutOfMemory(void* p, size_t nbytes)
TempAllocPolicy::onOutOfMemory(AllocFunction allocFunc, size_t nbytes, void* reallocPtr)
{
return static_cast<ExclusiveContext*>(cx_)->onOutOfMemory(p, nbytes);
return static_cast<ExclusiveContext*>(cx_)->onOutOfMemory(allocFunc, nbytes, reallocPtr);
}
void
+13 -6
View File
@@ -19,6 +19,12 @@
namespace js {
enum class AllocFunction {
Malloc,
Calloc,
Realloc
};
struct ContextFriendFields;
/* Policy for using system memory functions and doing no error reporting. */
@@ -51,14 +57,15 @@ class TempAllocPolicy
* Non-inline helper to call JSRuntime::onOutOfMemory with minimal
* code bloat.
*/
JS_FRIEND_API(void*) onOutOfMemory(void* p, size_t nbytes);
JS_FRIEND_API(void*) onOutOfMemory(AllocFunction allocFunc, size_t nbytes,
void* reallocPtr = nullptr);
template <typename T>
T* onOutOfMemoryTyped(void* p, size_t numElems) {
T* onOutOfMemoryTyped(AllocFunction allocFunc, size_t numElems) {
size_t bytes;
if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes)))
return nullptr;
return static_cast<T*>(onOutOfMemory(p, bytes));
return static_cast<T*>(onOutOfMemory(allocFunc, bytes));
}
public:
@@ -69,7 +76,7 @@ class TempAllocPolicy
T* pod_malloc(size_t numElems) {
T* p = js_pod_malloc<T>(numElems);
if (MOZ_UNLIKELY(!p))
p = onOutOfMemoryTyped<T>(nullptr, numElems);
p = onOutOfMemoryTyped<T>(AllocFunction::Malloc, numElems);
return p;
}
@@ -77,7 +84,7 @@ class TempAllocPolicy
T* pod_calloc(size_t numElems) {
T* p = js_pod_calloc<T>(numElems);
if (MOZ_UNLIKELY(!p))
p = onOutOfMemoryTyped<T>(reinterpret_cast<void*>(1), numElems);
p = onOutOfMemoryTyped<T>(AllocFunction::Calloc, numElems);
return p;
}
@@ -85,7 +92,7 @@ class TempAllocPolicy
T* pod_realloc(T* prior, size_t oldSize, size_t newSize) {
T* p2 = js_pod_realloc<T>(prior, oldSize, newSize);
if (MOZ_UNLIKELY(!p2))
p2 = onOutOfMemoryTyped<T>(p2, newSize);
p2 = onOutOfMemoryTyped<T>(AllocFunction::Realloc, newSize);
return p2;
}
+1 -2
View File
@@ -1447,8 +1447,7 @@ typedef void (*JSIterateCompartmentCallback)(JSRuntime* rt, void* data, JSCompar
/*
* This function calls |compartmentCallback| on every compartment. Beware that
* there is no guarantee that the compartment will survive after the callback
* returns. Also, if the callback can GC, there is no guarantee that every
* compartment will be visited.
* returns. Also, barriers are disabled via the TraceSession.
*/
extern JS_PUBLIC_API(void)
JS_IterateCompartments(JSRuntime* rt, void* data,
+2 -2
View File
@@ -161,8 +161,8 @@ class ExclusiveContext : public ContextFriendFields,
return thing->compartment() == compartment_;
}
void* onOutOfMemory(void* p, size_t nbytes) {
return runtime_->onOutOfMemory(p, nbytes, maybeJSContext());
void* onOutOfMemory(js::AllocFunction allocFunc, size_t nbytes, void* reallocPtr = nullptr) {
return runtime_->onOutOfMemory(allocFunc, nbytes, reallocPtr, maybeJSContext());
}
/* Clear the pending exception (if any) due to OOM. */
+3 -2
View File
@@ -476,9 +476,10 @@ JSCompartment::wrap(JSContext* cx, MutableHandle<PropertyDescriptor> desc)
* and when compacting to update cross-compartment pointers.
*/
void
JSCompartment::markCrossCompartmentWrappers(JSTracer *trc)
JSCompartment::markCrossCompartmentWrappers(JSTracer* trc)
{
MOZ_ASSERT(!zone()->isCollecting() || trc->runtime()->isHeapCompacting());
MOZ_ASSERT(trc->runtime()->isHeapMajorCollecting());
MOZ_ASSERT(!zone()->isCollecting() || trc->runtime()->gc.isHeapCompacting());
for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
Value v = e.front().value();
+18 -10
View File
@@ -1125,22 +1125,30 @@ js::detail::IdMatchesAtom(jsid id, JSAtom* atom)
return id == INTERNED_STRING_TO_JSID(nullptr, atom);
}
JS_FRIEND_API(JSContext*)
js::DefaultJSContext(JSRuntime* rt)
JS_FRIEND_API(bool)
js::PrepareScriptEnvironmentAndInvoke(JSRuntime* rt, HandleObject scope, ScriptEnvironmentPreparer::Closure& closure)
{
if (rt->defaultJSContextCallback) {
JSContext* cx = rt->defaultJSContextCallback(rt);
MOZ_ASSERT(cx);
return cx;
}
if (rt->scriptEnvironmentPreparer)
return rt->scriptEnvironmentPreparer->invoke(scope, closure);
MOZ_ASSERT(rt->contextList.getFirst() == rt->contextList.getLast());
return rt->contextList.getFirst();
JSContext* cx = rt->contextList.getFirst();
JSAutoCompartment ac(cx, scope);
bool ok = closure(cx);
// NB: This does not affect Gecko, which has a prepareScriptEnvironment
// callback.
if (JS_IsExceptionPending(cx)) {
JS_ReportPendingException(cx);
}
return ok;
}
JS_FRIEND_API(void)
js::SetDefaultJSContextCallback(JSRuntime* rt, DefaultJSContextCallback cb)
js::SetScriptEnvironmentPreparer(JSRuntime* rt, ScriptEnvironmentPreparer* preparer)
{
rt->defaultJSContextCallback = cb;
rt->scriptEnvironmentPreparer = preparer;
}
#ifdef DEBUG
+22 -8
View File
@@ -2590,18 +2590,32 @@ IdToValue(jsid id)
}
/*
* If the embedder has registered a default JSContext callback, returns the
* result of the callback. Otherwise, asserts that |rt| has exactly one
* JSContext associated with it, and returns that context.
* If the embedder has registered a ScriptEnvironmentPreparer,
* PrepareScriptEnvironmentAndInvoke will call the preparer's 'invoke' method
* with the given |closure|, with the assumption that the preparer will set up
* any state necessary to run script in |scope|, invoke |closure| with a valid
* JSContext*, and return.
*
* If no preparer is registered, PrepareScriptEnvironmentAndInvoke will assert
* that |rt| has exactly one JSContext associated with it, enter the compartment
* of |scope| on that context, and invoke |closure|.
*/
extern JS_FRIEND_API(JSContext*)
DefaultJSContext(JSRuntime* rt);
typedef JSContext*
(* DefaultJSContextCallback)(JSRuntime* rt);
struct ScriptEnvironmentPreparer {
struct Closure {
virtual bool operator()(JSContext* cx) = 0;
};
virtual bool invoke(JS::HandleObject scope, Closure& closure) = 0;
};
extern JS_FRIEND_API(bool)
PrepareScriptEnvironmentAndInvoke(JSRuntime* rt, JS::HandleObject scope,
ScriptEnvironmentPreparer::Closure& closure);
JS_FRIEND_API(void)
SetDefaultJSContextCallback(JSRuntime* rt, DefaultJSContextCallback cb);
SetScriptEnvironmentPreparer(JSRuntime* rt, ScriptEnvironmentPreparer*
preparer);
/*
* To help embedders enforce their invariants, we allow them to specify in
+21 -43
View File
@@ -1068,7 +1068,7 @@ GCRuntime::allocateArena(Chunk* chunk, Zone* zone, AllocKind thingKind, const Au
MOZ_ASSERT(chunk->hasAvailableArenas());
// Fail the allocation if we are over our heap size limits.
if (!isHeapMinorCollecting() &&
if (!rt->isHeapMinorCollecting() &&
!isHeapCompacting() &&
usage.gcBytes() >= tunables.gcMaxBytes())
{
@@ -1079,7 +1079,7 @@ GCRuntime::allocateArena(Chunk* chunk, Zone* zone, AllocKind thingKind, const Au
zone->usage.addGCArena();
// Trigger an incremental slice if needed.
if (!isHeapMinorCollecting() && !isHeapCompacting())
if (!rt->isHeapMinorCollecting() && !isHeapCompacting())
maybeAllocTriggerZoneGC(zone, lock);
return aheader;
@@ -1152,7 +1152,6 @@ GCRuntime::GCRuntime(JSRuntime* rt) :
manipulatingDeadZones(false),
objectsMarkedInDeadZones(0),
poked(false),
heapState(Idle),
#ifdef JS_GC_ZEAL
zealMode(0),
zealFrequency(0),
@@ -1530,7 +1529,7 @@ GCRuntime::getParameter(JSGCParamKey key, const AutoLockGC& lock)
void
GCRuntime::setMarkStackLimit(size_t limit)
{
MOZ_ASSERT(!isHeapBusy());
MOZ_ASSERT(!rt->isHeapBusy());
AutoStopVerifyingBarriers pauseVerification(rt, false);
marker.setMaxCapacity(limit);
}
@@ -2127,7 +2126,7 @@ ArenaLists::relocateArenas(ArenaHeader *&relocatedListOut, JS::gcreason::Reason
// This is only called from the main thread while we are doing a GC, so
// there is no need to lock.
MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
MOZ_ASSERT(runtime_->isHeapCompacting());
MOZ_ASSERT(runtime_->gc.isHeapCompacting());
MOZ_ASSERT(!runtime_->gc.isBackgroundSweeping());
// Flush all the freeLists back into the arena headers
@@ -3450,7 +3449,7 @@ GCRuntime::queueZonesForBackgroundSweep(ZoneList& zones)
void
GCRuntime::freeUnusedLifoBlocksAfterSweeping(LifoAlloc* lifo)
{
MOZ_ASSERT(isHeapBusy());
MOZ_ASSERT(rt->isHeapBusy());
AutoLockGC lock(rt);
freeLifoAlloc.transferUnusedFrom(lifo);
}
@@ -3458,7 +3457,7 @@ GCRuntime::freeUnusedLifoBlocksAfterSweeping(LifoAlloc* lifo)
void
GCRuntime::freeAllLifoBlocksAfterSweeping(LifoAlloc* lifo)
{
MOZ_ASSERT(isHeapBusy());
MOZ_ASSERT(rt->isHeapBusy());
AutoLockGC lock(rt);
freeLifoAlloc.transferFrom(lifo);
}
@@ -4306,17 +4305,6 @@ GCRuntime::finishMarkingValidation()
#endif
}
static void
AssertNeedsBarrierFlagsConsistent(JSRuntime* rt)
{
#ifdef JS_GC_MARKING_VALIDATION
bool anyNeedsBarrier = false;
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
anyNeedsBarrier |= zone->needsIncrementalBarrier();
MOZ_ASSERT(rt->needsIncrementalBarrier() == anyNeedsBarrier);
#endif
}
static void
DropStringWrappers(JSRuntime* rt)
{
@@ -4482,8 +4470,6 @@ GCRuntime::getNextZoneGroup()
zone->setGCState(Zone::NoGC);
zone->gcGrayRoots.clearAndFree();
}
rt->setNeedsIncrementalBarrier(false);
AssertNeedsBarrierFlagsConsistent(rt);
for (GCCompartmentGroupIter comp(rt); !comp.done(); comp.next())
ResetGrayList(comp);
@@ -5521,14 +5507,14 @@ GCRuntime::finishCollection(JS::gcreason::Reason reason)
}
/* Start a new heap session. */
AutoTraceSession::AutoTraceSession(JSRuntime* rt, js::HeapState heapState)
AutoTraceSession::AutoTraceSession(JSRuntime* rt, JS::HeapState heapState)
: lock(rt),
runtime(rt),
prevState(rt->gc.heapState)
prevState(rt->heapState_)
{
MOZ_ASSERT(rt->gc.heapState == Idle);
MOZ_ASSERT(heapState != Idle);
MOZ_ASSERT_IF(heapState == MajorCollecting, rt->gc.nursery.isEmpty());
MOZ_ASSERT(rt->heapState_ == JS::HeapState::Idle);
MOZ_ASSERT(heapState != JS::HeapState::Idle);
MOZ_ASSERT_IF(heapState == JS::HeapState::MajorCollecting, rt->gc.nursery.isEmpty());
// Threads with an exclusive context can hit refillFreeList while holding
// the exclusive access lock. To avoid deadlocking when we try to acquire
@@ -5540,9 +5526,9 @@ AutoTraceSession::AutoTraceSession(JSRuntime* rt, js::HeapState heapState)
// Lock the helper thread state when changing the heap state in the
// presence of exclusive threads, to avoid racing with refillFreeList.
AutoLockHelperThreadState lock;
rt->gc.heapState = heapState;
rt->heapState_ = heapState;
} else {
rt->gc.heapState = heapState;
rt->heapState_ = heapState;
}
}
@@ -5552,12 +5538,12 @@ AutoTraceSession::~AutoTraceSession()
if (runtime->exclusiveThreadsPresent()) {
AutoLockHelperThreadState lock;
runtime->gc.heapState = prevState;
runtime->heapState_ = prevState;
// Notify any helper threads waiting for the trace session to end.
HelperThreadState().notifyAll(GlobalHelperThreadState::PRODUCER);
} else {
runtime->gc.heapState = prevState;
runtime->heapState_ = prevState;
}
}
@@ -5614,8 +5600,6 @@ GCRuntime::resetIncrementalGC(const char* reason)
zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit);
zone->setGCState(Zone::NoGC);
}
rt->setNeedsIncrementalBarrier(false);
AssertNeedsBarrierFlagsConsistent(rt);
freeLifoAlloc.freeAll();
@@ -5727,25 +5711,19 @@ AutoGCSlice::AutoGCSlice(JSRuntime* rt)
MOZ_ASSERT(!zone->needsIncrementalBarrier());
}
}
rt->setNeedsIncrementalBarrier(false);
AssertNeedsBarrierFlagsConsistent(rt);
}
AutoGCSlice::~AutoGCSlice()
{
/* We can't use GCZonesIter if this is the end of the last slice. */
bool haveBarriers = false;
for (ZonesIter zone(runtime, WithAtoms); !zone.done(); zone.next()) {
if (zone->isGCMarking()) {
zone->setNeedsIncrementalBarrier(true, Zone::UpdateJit);
zone->arenas.prepareForIncrementalGC(runtime);
haveBarriers = true;
} else {
zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit);
}
}
runtime->setNeedsIncrementalBarrier(haveBarriers);
AssertNeedsBarrierFlagsConsistent(runtime);
}
void
@@ -6008,7 +5986,7 @@ GCRuntime::gcCycle(bool incremental, SliceBudget& budget, JS::gcreason::Reason r
*/
AutoDisableStoreBuffer adsb(this);
AutoTraceSession session(rt, MajorCollecting);
AutoTraceSession session(rt, JS::HeapState::MajorCollecting);
majorGCTriggerReason = JS::gcreason::NO_REASON;
interFrameGC = true;
@@ -6278,7 +6256,7 @@ GCRuntime::abortGC()
evictNursery(JS::gcreason::ABORT_GC);
AutoDisableStoreBuffer adsb(this);
AutoTraceSession session(rt, MajorCollecting);
AutoTraceSession session(rt, JS::HeapState::MajorCollecting);
number++;
resetIncrementalGC("abort");
@@ -6665,14 +6643,14 @@ GCRuntime::runDebugGC()
void
GCRuntime::setValidate(bool enabled)
{
MOZ_ASSERT(!isHeapMajorCollecting());
MOZ_ASSERT(!rt->isHeapMajorCollecting());
validate = enabled;
}
void
GCRuntime::setFullCompartmentChecks(bool enabled)
{
MOZ_ASSERT(!isHeapMajorCollecting());
MOZ_ASSERT(!rt->isHeapMajorCollecting());
fullCompartmentChecks = enabled;
}
@@ -6680,7 +6658,7 @@ GCRuntime::setFullCompartmentChecks(bool enabled)
bool
GCRuntime::selectForMarking(JSObject* object)
{
MOZ_ASSERT(!isHeapMajorCollecting());
MOZ_ASSERT(!rt->isHeapMajorCollecting());
return selectedForMarking.append(object);
}
@@ -6693,7 +6671,7 @@ GCRuntime::clearSelectedForMarking()
void
GCRuntime::setDeterministic(bool enabled)
{
MOZ_ASSERT(!isHeapMajorCollecting());
MOZ_ASSERT(!rt->isHeapMajorCollecting());
deterministicOnly = enabled;
}
#endif
-7
View File
@@ -39,13 +39,6 @@ namespace js {
unsigned GetCPUCount();
enum HeapState {
Idle, // doing nothing with the GC heap
Tracing, // tracing the GC heap without collecting, e.g. IterateCompartments()
MajorCollecting, // doing a GC of the major heap
MinorCollecting // doing a GC of the minor heap (nursery)
};
enum ThreadType
{
MainThread,
+14 -5
View File
@@ -128,6 +128,7 @@ namespace js {
void FinishGC(JSRuntime* rt);
namespace gc {
class AutoTraceSession;
class StoreBuffer;
void MarkPersistentRootedChains(JSTracer*);
void FinishPersistentRootedChains(JSRuntime*);
@@ -138,24 +139,32 @@ namespace JS {
typedef void (*OffThreadCompileCallback)(void* token, void* callbackData);
enum class HeapState {
Idle, // doing nothing with the GC heap
Tracing, // tracing the GC heap without collecting, e.g. IterateCompartments()
MajorCollecting, // doing a GC of the major heap
MinorCollecting // doing a GC of the minor heap (nursery)
};
namespace shadow {
struct Runtime
{
/* Restrict zone access during Minor GC. */
bool needsIncrementalBarrier_;
protected:
// Allow inlining of heapState checks.
friend class js::gc::AutoTraceSession;
JS::HeapState heapState_;
private:
js::gc::StoreBuffer* gcStoreBufferPtr_;
public:
Runtime()
: needsIncrementalBarrier_(false)
: heapState_(JS::HeapState::Idle)
, gcStoreBufferPtr_(nullptr)
{}
bool needsIncrementalBarrier() const {
return needsIncrementalBarrier_;
return heapState_ == JS::HeapState::Idle;
}
js::gc::StoreBuffer* gcStoreBufferPtr() { return gcStoreBufferPtr_; }
+2 -2
View File
@@ -68,8 +68,8 @@ for (var constructor of constructors) {
mathConstructor.constructor = Math.sin;
assertDeepEq(mathConstructor.slice(4), new constructor(4));
assertEq("species" in Symbol, false,
"you've implemented @@species -- add real tests here!");
assertEq(Symbol.species in Int8Array, false,
"you've implemented %TypedArray%[@@species] -- add real tests here!");
}
if (typeof reportCompare === "function")
+2
View File
@@ -215,6 +215,8 @@ class Test:
test.test_join.append([name[len('test-join='):]])
elif name == 'ion-eager':
test.jitflags.append('--ion-eager')
elif name == 'baseline-eager':
test.jitflags.append('--baseline-eager')
elif name == 'dump-bytecode':
test.jitflags.append('--dump-bytecode')
elif name.startswith('--'):
+5 -5
View File
@@ -69,7 +69,7 @@ struct MallocProvider
client()->reportAllocationOverflow();
return nullptr;
}
return static_cast<T*>(client()->onOutOfMemory(nullptr, bytes));
return static_cast<T*>(client()->onOutOfMemory(AllocFunction::Malloc, bytes));
}
template <class T, class U>
@@ -84,7 +84,7 @@ struct MallocProvider
client()->updateMallocCounter(bytes);
return p;
}
return static_cast<T*>(client()->onOutOfMemory(nullptr, bytes));
return static_cast<T*>(client()->onOutOfMemory(AllocFunction::Malloc, bytes));
}
template <class T>
@@ -110,7 +110,7 @@ struct MallocProvider
client()->reportAllocationOverflow();
return nullptr;
}
return static_cast<T*>(client()->onOutOfMemory(nullptr, bytes));
return static_cast<T*>(client()->onOutOfMemory(AllocFunction::Calloc, bytes));
}
template <class T, class U>
@@ -125,7 +125,7 @@ struct MallocProvider
client()->updateMallocCounter(bytes);
return p;
}
return static_cast<T*>(client()->onOutOfMemory(nullptr, bytes));
return static_cast<T*>(client()->onOutOfMemory(AllocFunction::Calloc, bytes));
}
template <class T>
@@ -150,7 +150,7 @@ struct MallocProvider
client()->reportAllocationOverflow();
return nullptr;
}
return static_cast<T*>(client()->onOutOfMemory(prior, bytes));
return static_cast<T*>(client()->onOutOfMemory(AllocFunction::Realloc, bytes));
}
JS_DECLARE_NEW_METHODS(new_, pod_malloc<uint8_t>, MOZ_ALWAYS_INLINE)
+2 -1
View File
@@ -933,7 +933,8 @@ RegExpCompartment::sweep(JSRuntime* rt)
keep = false;
}
}
if (keep || rt->isHeapCompacting()) {
MOZ_ASSERT(rt->isHeapMajorCollecting());
if (keep || rt->gc.isHeapCompacting()) {
shared->clearMarked();
} else {
js_delete(shared);
+21 -15
View File
@@ -207,7 +207,7 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
jitSupportsFloatingPoint(false),
jitSupportsSimd(false),
ionPcScriptCache(nullptr),
defaultJSContextCallback(nullptr),
scriptEnvironmentPreparer(nullptr),
ctypesActivityCallback(nullptr),
offthreadIonCompilationEnabled_(true),
parallelParsingEnabled_(true),
@@ -727,14 +727,11 @@ JSRuntime::onTooMuchMalloc()
}
JS_FRIEND_API(void*)
JSRuntime::onOutOfMemory(void* p, size_t nbytes)
JSRuntime::onOutOfMemory(AllocFunction allocFunc, size_t nbytes, void* reallocPtr,
JSContext* maybecx)
{
return onOutOfMemory(p, nbytes, nullptr);
}
MOZ_ASSERT_IF(allocFunc != AllocFunction::Realloc, !reallocPtr);
JS_FRIEND_API(void*)
JSRuntime::onOutOfMemory(void* p, size_t nbytes, JSContext* cx)
{
if (isHeapBusy())
return nullptr;
@@ -743,25 +740,34 @@ JSRuntime::onOutOfMemory(void* p, size_t nbytes, JSContext* cx)
* all the allocations and released the empty GC chunks.
*/
gc.onOutOfMallocMemory();
if (!p)
void* p;
switch (allocFunc) {
case AllocFunction::Malloc:
p = js_malloc(nbytes);
else if (p == reinterpret_cast<void*>(1))
break;
case AllocFunction::Calloc:
p = js_calloc(nbytes);
else
p = js_realloc(p, nbytes);
break;
case AllocFunction::Realloc:
p = js_realloc(reallocPtr, nbytes);
break;
default:
MOZ_CRASH();
}
if (p)
return p;
if (cx)
ReportOutOfMemory(cx);
if (maybecx)
ReportOutOfMemory(maybecx);
return nullptr;
}
void*
JSRuntime::onOutOfMemoryCanGC(void* p, size_t bytes)
JSRuntime::onOutOfMemoryCanGC(AllocFunction allocFunc, size_t bytes, void* reallocPtr)
{
if (largeAllocationFailureCallback && bytes >= LARGE_ALLOCATION)
largeAllocationFailureCallback(largeAllocationFailureCallbackData);
return onOutOfMemory(p, bytes);
return onOutOfMemory(allocFunc, bytes, reallocPtr);
}
bool
+32 -21
View File
@@ -709,18 +709,34 @@ struct JSRuntime : public JS::shadow::Runtime,
uint32_t profilerSampleBufferGen() {
return profilerSampleBufferGen_;
}
void resetProfilerSampleBufferGen() {
profilerSampleBufferGen_ = 0;
}
void setProfilerSampleBufferGen(uint32_t gen) {
profilerSampleBufferGen_ = gen;
// May be called from sampler thread or signal handler; use
// compareExchange to make sure we have monotonic increase.
for (;;) {
uint32_t curGen = profilerSampleBufferGen_;
if (curGen >= gen)
break;
if (profilerSampleBufferGen_.compareExchange(curGen, gen))
break;
}
}
uint32_t profilerSampleBufferLapCount() {
MOZ_ASSERT(profilerSampleBufferLapCount_ > 0);
return profilerSampleBufferLapCount_;
}
void resetProfilerSampleBufferLapCount() {
profilerSampleBufferLapCount_ = 1;
}
void updateProfilerSampleBufferLapCount(uint32_t lapCount) {
MOZ_ASSERT(profilerSampleBufferLapCount_ > 0);
// Use compareExchange to make sure we have monotonic increase.
// May be called from sampler thread or signal handler; use
// compareExchange to make sure we have monotonic increase.
for (;;) {
uint32_t curLapCount = profilerSampleBufferLapCount_;
if (curLapCount >= lapCount)
@@ -984,11 +1000,10 @@ struct JSRuntime : public JS::shadow::Runtime,
/* Garbage collector state has been sucessfully initialized. */
bool gcInitialized;
bool isHeapBusy() { return gc.isHeapBusy(); }
bool isHeapMajorCollecting() { return gc.isHeapMajorCollecting(); }
bool isHeapMinorCollecting() { return gc.isHeapMinorCollecting(); }
bool isHeapCollecting() { return gc.isHeapCollecting(); }
bool isHeapCompacting() { return gc.isHeapCompacting(); }
bool isHeapBusy() const { return heapState_ != JS::HeapState::Idle; }
bool isHeapMajorCollecting() const { return heapState_ == JS::HeapState::MajorCollecting; }
bool isHeapMinorCollecting() const { return heapState_ == JS::HeapState::MinorCollecting; }
bool isHeapCollecting() const { return isHeapMinorCollecting() || isHeapMajorCollecting(); }
int gcZeal() { return gc.zeal(); }
@@ -1006,10 +1021,6 @@ struct JSRuntime : public JS::shadow::Runtime,
#endif
public:
void setNeedsIncrementalBarrier(bool needs) {
needsIncrementalBarrier_ = needs;
}
#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
js::jit::Simulator* simulator() const;
uintptr_t* addressOfSimulatorStackLimit();
@@ -1308,7 +1319,7 @@ struct JSRuntime : public JS::shadow::Runtime,
// Cache for jit::GetPcScript().
js::jit::PcScriptCache* ionPcScriptCache;
js::DefaultJSContextCallback defaultJSContextCallback;
js::ScriptEnvironmentPreparer* scriptEnvironmentPreparer;
js::CTypesActivityCallback ctypesActivityCallback;
@@ -1346,18 +1357,18 @@ struct JSRuntime : public JS::shadow::Runtime,
JS_FRIEND_API(void) onTooMuchMalloc();
/*
* This should be called after system malloc/realloc returns nullptr to try
* to recove some memory or to report an error. Failures in malloc and
* calloc are signaled by p == null and p == reinterpret_cast<void*>(1).
* Other values of p mean a realloc failure.
* This should be called after system malloc/calloc/realloc returns nullptr
* to try to recove some memory or to report an error. For realloc, the
* original pointer must be passed as reallocPtr.
*
* The function must be called outside the GC lock.
*/
JS_FRIEND_API(void*) onOutOfMemory(void* p, size_t nbytes);
JS_FRIEND_API(void*) onOutOfMemory(void* p, size_t nbytes, JSContext* cx);
JS_FRIEND_API(void*) onOutOfMemory(js::AllocFunction allocator, size_t nbytes,
void* reallocPtr = nullptr, JSContext* maybecx = nullptr);
/* onOutOfMemory but can call the largeAllocationFailureCallback. */
JS_FRIEND_API(void*) onOutOfMemoryCanGC(void* p, size_t bytes);
JS_FRIEND_API(void*) onOutOfMemoryCanGC(js::AllocFunction allocator, size_t nbytes,
void* reallocPtr = nullptr);
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* runtime);
@@ -1422,7 +1433,7 @@ struct JSRuntime : public JS::shadow::Runtime,
reportAllocationOverflow();
return nullptr;
}
return static_cast<T*>(onOutOfMemoryCanGC(reinterpret_cast<void*>(1), bytes));
return static_cast<T*>(onOutOfMemoryCanGC(js::AllocFunction::Calloc, bytes));
}
template <typename T>
@@ -1435,7 +1446,7 @@ struct JSRuntime : public JS::shadow::Runtime,
reportAllocationOverflow();
return nullptr;
}
return static_cast<T*>(onOutOfMemoryCanGC(p, bytes));
return static_cast<T*>(onOutOfMemoryCanGC(js::AllocFunction::Realloc, bytes));
}
/*
+12 -2
View File
@@ -14,6 +14,7 @@
#include "jit/BaselineFrame.h"
#include "jit/BaselineJIT.h"
#include "jit/JitcodeMap.h"
#include "jit/JitFrameIterator.h"
#include "jit/JitFrames.h"
#include "vm/StringBuffer.h"
@@ -87,6 +88,15 @@ SPSProfiler::enable(bool enabled)
*/
ReleaseAllJITCode(rt->defaultFreeOp());
// This function is called when the Gecko profiler makes a new TableTicker
// (and thus, a new circular buffer). Set all current entries in the
// JitcodeGlobalTable as expired and reset the buffer generation and lap
// count.
if (rt->hasJitRuntime() && rt->jitRuntime()->hasJitcodeGlobalTable())
rt->jitRuntime()->getJitcodeGlobalTable()->setAllEntriesAsExpired(rt);
rt->resetProfilerSampleBufferGen();
rt->resetProfilerSampleBufferLapCount();
// Ensure that lastProfilingFrame is null before 'enabled' becomes true.
if (rt->jitActivation) {
rt->jitActivation->setLastProfilingFrame(nullptr);
@@ -449,8 +459,8 @@ AutoSuppressProfilerSampling::AutoSuppressProfilerSampling(JSRuntime* rt
AutoSuppressProfilerSampling::~AutoSuppressProfilerSampling()
{
if (previouslyEnabled_)
rt_->enableProfilerSampling();
if (previouslyEnabled_)
rt_->enableProfilerSampling();
}
void*
+2 -1
View File
@@ -337,7 +337,8 @@ UnboxedPlainObject::ensureExpando(JSContext* cx, Handle<UnboxedPlainObject*> obj
if (obj->expando_)
return obj->expando_;
UnboxedExpandoObject* expando = NewObjectWithGivenProto<UnboxedExpandoObject>(cx, nullptr);
UnboxedExpandoObject* expando =
NewObjectWithGivenProto<UnboxedExpandoObject>(cx, nullptr, AllocKind::OBJECT4);
if (!expando)
return nullptr;
+15 -22
View File
@@ -26,6 +26,7 @@
#include "nsPrintfCString.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/dom/ScriptSettings.h"
#include "nsContentUtils.h"
#include "nsCCUncollectableMarker.h"
@@ -54,6 +55,7 @@ using namespace mozilla;
using namespace xpc;
using namespace JS;
using mozilla::dom::PerThreadAtomCache;
using mozilla::dom::AutoEntryScript;
/***************************************************************************/
@@ -1338,11 +1340,15 @@ xpc::SimulateActivityCallback(bool aActive)
}
// static
JSContext*
XPCJSRuntime::DefaultJSContextCallback(JSRuntime* rt)
bool
XPCJSRuntime::EnvironmentPreparer::invoke(HandleObject scope, js::ScriptEnvironmentPreparer::Closure& closure)
{
MOZ_ASSERT(rt == Get()->Runtime());
return Get()->GetJSContextStack()->GetSafeJSContext();
MOZ_ASSERT(NS_IsMainThread());
nsIGlobalObject* global = NativeGlobal(scope);
NS_ENSURE_TRUE(global && global->GetGlobalJSObject(), false);
AutoEntryScript aes(global, "JS-engine-initiated execution");
aes.TakeOwnershipOfErrorReporting();
return closure(aes.cx());
}
// static
@@ -1357,22 +1363,6 @@ XPCJSRuntime::ActivityCallback(void* arg, bool active)
self->mWatchdogManager->RecordRuntimeActivity(active);
}
// static
//
// JS-CTypes creates and caches a JSContext that it uses when executing JS
// callbacks. When we're notified that ctypes is about to call into some JS,
// push the cx to maintain the integrity of the context stack.
void
XPCJSRuntime::CTypesActivityCallback(JSContext* cx, js::CTypesActivityType type)
{
if (type == js::CTYPES_CALLBACK_BEGIN) {
if (!xpc::PushJSContextNoScriptContext(cx))
MOZ_CRASH();
} else if (type == js::CTYPES_CALLBACK_END) {
xpc::PopJSContextNoScriptContext();
}
}
// static
bool
XPCJSRuntime::InterruptCallback(JSContext* cx)
@@ -3395,9 +3385,12 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
JS_AddWeakPointerCallback(runtime, WeakPointerCallback, this);
JS_SetWrapObjectCallbacks(runtime, &WrapObjectCallbacks);
js::SetPreserveWrapperCallback(runtime, PreserveWrapper);
js::SetDefaultJSContextCallback(runtime, DefaultJSContextCallback);
#ifdef MOZ_ENABLE_PROFILER_SPS
if (PseudoStack* stack = mozilla_get_pseudo_stack())
stack->sampleRuntime(runtime);
#endif
js::SetScriptEnvironmentPreparer(runtime, &mEnvironmentPreparer);
js::SetActivityCallback(runtime, ActivityCallback, this);
js::SetCTypesActivityCallback(runtime, CTypesActivityCallback);
JS_SetInterruptCallback(runtime, InterruptCallback);
// The JS engine needs to keep the source code around in order to implement
+6 -6
View File
@@ -974,7 +974,7 @@ nsXPConnect::OnProcessNextEvent(nsIThreadInternal* aThread, bool aMayWait,
// Push a null JSContext so that we don't see any script during
// event processing.
bool ok = PushJSContextNoScriptContext(nullptr);
bool ok = PushNullJSContext();
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
return NS_OK;
}
@@ -1000,7 +1000,7 @@ nsXPConnect::AfterProcessNextEvent(nsIThreadInternal* aThread,
Promise::PerformMicroTaskCheckpoint();
PopJSContextNoScriptContext();
PopNullJSContext();
return NS_OK;
}
@@ -1080,15 +1080,15 @@ nsXPConnect::GetSafeJSContext()
namespace xpc {
bool
PushJSContextNoScriptContext(JSContext* aCx)
PushNullJSContext()
{
MOZ_ASSERT_IF(aCx, !GetScriptContextFromJSContext(aCx));
return XPCJSRuntime::Get()->GetJSContextStack()->Push(aCx);
return XPCJSRuntime::Get()->GetJSContextStack()->Push(nullptr);
}
void
PopJSContextNoScriptContext()
PopNullJSContext()
{
MOZ_ASSERT(XPCJSRuntime::Get()->GetJSContextStack()->Peek() == nullptr);
XPCJSRuntime::Get()->GetJSContextStack()->Pop();
}
+9 -13
View File
@@ -611,10 +611,12 @@ public:
void AddContextCallback(xpcContextCallback cb);
void RemoveContextCallback(xpcContextCallback cb);
static JSContext* DefaultJSContextCallback(JSRuntime* rt);
struct EnvironmentPreparer : public js::ScriptEnvironmentPreparer {
bool invoke(JS::HandleObject scope, Closure& closure) override;
};
EnvironmentPreparer mEnvironmentPreparer;
static void ActivityCallback(void* arg, bool active);
static void CTypesActivityCallback(JSContext* cx,
js::CTypesActivityType type);
static bool InterruptCallback(JSContext* cx);
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
@@ -2848,14 +2850,8 @@ struct XPCJSContextInfo {
};
namespace xpc {
// These functions are used in a few places where a callback model makes it
// impossible to push a JSContext using one of our stack-scoped classes. We
// depend on those stack-scoped classes to maintain nsIScriptContext
// invariants, so these functions may only be used of the context is not
// associated with an nsJSContext/nsIScriptContext.
bool PushJSContextNoScriptContext(JSContext* aCx);
void PopJSContextNoScriptContext();
bool PushNullJSContext();
void PopNullJSContext();
} /* namespace xpc */
@@ -2896,8 +2892,8 @@ public:
private:
friend class mozilla::dom::danger::AutoCxPusher;
friend bool xpc::PushJSContextNoScriptContext(JSContext* aCx);
friend void xpc::PopJSContextNoScriptContext();
friend bool xpc::PushNullJSContext();
friend void xpc::PopNullJSContext();
// We make these private so that stack manipulation can only happen
// through one of the above friends.
+4 -1
View File
@@ -785,7 +785,10 @@ void mergeStacksIntoProfile(ThreadProfile& aProfile, TickSample* aSample, Native
uint32_t lapCount = aProfile.bufferGeneration() - startBufferGen;
// Update the JS runtime with the current profile sample buffer generation.
if (pseudoStack->mRuntime) {
//
// Do not do this for synchronous sampling, which create their own
// ProfileBuffers.
if (!aSample->isSamplingCurrentThread && pseudoStack->mRuntime) {
JS::UpdateJSRuntimeProfilerSampleBufferGen(pseudoStack->mRuntime,
aProfile.bufferGeneration(),
lapCount);