mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
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:
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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_; }
|
||||
|
||||
@@ -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);
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
@@ -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();
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+201
-97
@@ -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.");
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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: {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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. */
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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_; }
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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('--'):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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*
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user