mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 15:23:51 +00:00
Bug 1281529 part 9 - Move JSRuntime caches into a new ContextCaches class. r=jorendorff
--HG-- rename : js/src/vm/Runtime-inl.h => js/src/vm/Caches-inl.h
This commit is contained in:
parent
8b89bcc511
commit
d051fdf152
@ -93,7 +93,7 @@ class EvalScriptGuard
|
||||
EvalCacheEntry cacheEntry = {lookupStr_, script_, lookup_.callerScript, lookup_.pc};
|
||||
lookup_.str = lookupStr_;
|
||||
if (lookup_.str && IsEvalCacheCandidate(script_)) {
|
||||
bool ok = cx_->runtime()->evalCache.relookupOrAdd(p_, lookup_, cacheEntry);
|
||||
bool ok = cx_->caches.evalCache.relookupOrAdd(p_, lookup_, cacheEntry);
|
||||
(void)ok; // Ignore failure to add cache entry.
|
||||
}
|
||||
}
|
||||
@ -106,10 +106,10 @@ class EvalScriptGuard
|
||||
lookup_.callerScript = callerScript;
|
||||
lookup_.version = cx_->findVersion();
|
||||
lookup_.pc = pc;
|
||||
p_ = cx_->runtime()->evalCache.lookupForAdd(lookup_);
|
||||
p_ = cx_->caches.evalCache.lookupForAdd(lookup_);
|
||||
if (p_) {
|
||||
script_ = p_->script;
|
||||
cx_->runtime()->evalCache.remove(p_);
|
||||
cx_->caches.evalCache.remove(p_);
|
||||
script_->uncacheForEval();
|
||||
}
|
||||
}
|
||||
|
@ -451,7 +451,7 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList
|
||||
TIME_END(markDebugger);
|
||||
|
||||
TIME_START(clearNewObjectCache);
|
||||
rt->newObjectCache.clearNurseryObjects(rt);
|
||||
rt->contextFromMainThread()->caches.newObjectCache.clearNurseryObjects(rt);
|
||||
TIME_END(clearNewObjectCache);
|
||||
|
||||
// Most of the work is done here. This loop iterates over objects that have
|
||||
|
@ -47,7 +47,7 @@ BaselineCompiler::BaselineCompiler(JSContext* cx, TempAllocator& alloc, JSScript
|
||||
bool
|
||||
BaselineCompiler::init()
|
||||
{
|
||||
if (!analysis_.init(alloc_, cx->runtime()->gsnCache))
|
||||
if (!analysis_.init(alloc_, cx->caches.gsnCache))
|
||||
return false;
|
||||
|
||||
if (!labels_.init(alloc_, script->length()))
|
||||
|
@ -290,7 +290,7 @@ DoTypeUpdateFallback(JSContext* cx, BaselineFrame* frame, ICUpdatedStub* stub, H
|
||||
MOZ_ASSERT(obj->isNative() || obj->is<UnboxedPlainObject>());
|
||||
jsbytecode* pc = stub->getChainFallback()->icEntry()->pc(script);
|
||||
if (*pc == JSOP_SETALIASEDVAR || *pc == JSOP_INITALIASEDLEXICAL)
|
||||
id = NameToId(ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc));
|
||||
id = NameToId(ScopeCoordinateName(cx->caches.scopeCoordinateNameCache, script, pc));
|
||||
else
|
||||
id = NameToId(script->getName(pc));
|
||||
AddTypePropertyId(cx, obj, id, value);
|
||||
@ -4495,7 +4495,7 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_
|
||||
|
||||
RootedPropertyName name(cx);
|
||||
if (op == JSOP_SETALIASEDVAR || op == JSOP_INITALIASEDLEXICAL)
|
||||
name = ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc);
|
||||
name = ScopeCoordinateName(cx->caches.scopeCoordinateNameCache, script, pc);
|
||||
else
|
||||
name = script->getName(pc);
|
||||
RootedId id(cx, NameToId(name));
|
||||
|
@ -77,7 +77,7 @@ CompileRuntime::addressOfActivation()
|
||||
const void*
|
||||
CompileRuntime::addressOfLastCachedNativeIterator()
|
||||
{
|
||||
return &runtime()->nativeIterCache.last;
|
||||
return &static_cast<JSContext*>(runtime())->caches.nativeIterCache.last;
|
||||
}
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
@ -187,12 +187,6 @@ CompileRuntime::DOMcallbacks()
|
||||
return GetDOMCallbacks(runtime());
|
||||
}
|
||||
|
||||
const MathCache*
|
||||
CompileRuntime::maybeGetMathCache()
|
||||
{
|
||||
return runtime()->maybeGetMathCache();
|
||||
}
|
||||
|
||||
const Nursery&
|
||||
CompileRuntime::gcNursery()
|
||||
{
|
||||
|
@ -88,8 +88,6 @@ class CompileRuntime
|
||||
// DOM callbacks must be threadsafe (and will hopefully be removed soon).
|
||||
const DOMCallbacks* DOMcallbacks();
|
||||
|
||||
const MathCache* maybeGetMathCache();
|
||||
|
||||
const Nursery& gcNursery();
|
||||
void setMinorGCShouldCancelIonCompilations();
|
||||
};
|
||||
|
@ -431,7 +431,7 @@ IonBuilder::inlineMathFunction(CallInfo& callInfo, MMathFunction::Function funct
|
||||
if (!IsNumberType(callInfo.getArg(0)->type()))
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
const MathCache* cache = compartment->runtime()->maybeGetMathCache();
|
||||
const MathCache* cache = GetJSContextFromMainThread()->caches.maybeGetMathCache();
|
||||
|
||||
callInfo.fun()->setImplicitlyUsedUnchecked();
|
||||
callInfo.thisArg()->setImplicitlyUsedUnchecked();
|
||||
|
@ -42,9 +42,9 @@
|
||||
|
||||
#include "vm/ArgumentsObject-inl.h"
|
||||
#include "vm/ArrayObject-inl.h"
|
||||
#include "vm/Caches-inl.h"
|
||||
#include "vm/Interpreter-inl.h"
|
||||
#include "vm/NativeObject-inl.h"
|
||||
#include "vm/Runtime-inl.h"
|
||||
#include "vm/UnboxedObject-inl.h"
|
||||
|
||||
using namespace js;
|
||||
@ -3386,8 +3386,7 @@ NewArray(ExclusiveContext* cxArg, uint32_t length,
|
||||
bool isCachable = NewObjectWithTaggedProtoIsCachable(cxArg, taggedProto, newKind, &ArrayObject::class_);
|
||||
if (isCachable) {
|
||||
JSContext* cx = cxArg->asJSContext();
|
||||
JSRuntime* rt = cx->runtime();
|
||||
NewObjectCache& cache = rt->newObjectCache;
|
||||
NewObjectCache& cache = cx->caches.newObjectCache;
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
if (cache.lookupProto(&ArrayObject::class_, proto, allocKind, &entry)) {
|
||||
gc::InitialHeap heap = GetInitialHeap(newKind, &ArrayObject::class_);
|
||||
@ -3441,7 +3440,7 @@ NewArray(ExclusiveContext* cxArg, uint32_t length,
|
||||
return nullptr;
|
||||
|
||||
if (isCachable) {
|
||||
NewObjectCache& cache = cxArg->asJSContext()->runtime()->newObjectCache;
|
||||
NewObjectCache& cache = cxArg->asJSContext()->caches.newObjectCache;
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
cache.lookupProto(&ArrayObject::class_, proto, allocKind, &entry);
|
||||
cache.fillProto(entry, &ArrayObject::class_, taggedProto, allocKind, arr);
|
||||
|
@ -93,6 +93,9 @@ JSContext::init(uint32_t maxBytes, uint32_t maxNurseryBytes)
|
||||
if (!JSRuntime::init(maxBytes, maxNurseryBytes))
|
||||
return false;
|
||||
|
||||
if (!caches.init())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "js/GCVector.h"
|
||||
#include "js/Vector.h"
|
||||
#include "vm/Caches.h"
|
||||
#include "vm/Runtime.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@ -359,6 +360,8 @@ struct JSContext : public js::ExclusiveContext,
|
||||
js::jit::DebugModeOSRVolatileJitFrameIterator* liveVolatileJitFrameIterators_;
|
||||
|
||||
public:
|
||||
js::ContextCaches caches;
|
||||
|
||||
int32_t reportGranularity; /* see vm/Probes.h */
|
||||
|
||||
js::AutoResolving* resolvingList;
|
||||
|
@ -1480,7 +1480,7 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext* cx, HandleFuncti
|
||||
// has started.
|
||||
if (canRelazify && !JS::IsIncrementalGCInProgress(cx->runtime())) {
|
||||
LazyScriptCache::Lookup lookup(cx, lazy);
|
||||
cx->runtime()->lazyScriptCache.lookup(lookup, script.address());
|
||||
cx->caches.lazyScriptCache.lookup(lookup, script.address());
|
||||
}
|
||||
|
||||
if (script) {
|
||||
@ -1534,7 +1534,7 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext* cx, HandleFuncti
|
||||
script->setColumn(lazy->column());
|
||||
|
||||
LazyScriptCache::Lookup lookup(cx, lazy);
|
||||
cx->runtime()->lazyScriptCache.insert(lookup, script);
|
||||
cx->caches.lazyScriptCache.insert(lookup, script);
|
||||
|
||||
// Remember the lazy script on the compiled script, so it can be
|
||||
// stored on the function again in case of re-lazification.
|
||||
|
@ -3614,12 +3614,15 @@ GCRuntime::purgeRuntime(AutoLockForExclusiveAccess& lock)
|
||||
freeUnusedLifoBlocksAfterSweeping(&rt->tempLifoAlloc);
|
||||
|
||||
rt->interpreterStack().purge(rt);
|
||||
rt->gsnCache.purge();
|
||||
rt->scopeCoordinateNameCache.purge();
|
||||
rt->newObjectCache.purge();
|
||||
rt->nativeIterCache.purge();
|
||||
rt->uncompressedSourceCache.purge();
|
||||
rt->evalCache.clear();
|
||||
|
||||
JSContext* cx = rt->contextFromMainThread();
|
||||
cx->caches.gsnCache.purge();
|
||||
cx->caches.scopeCoordinateNameCache.purge();
|
||||
cx->caches.newObjectCache.purge();
|
||||
cx->caches.nativeIterCache.purge();
|
||||
cx->caches.uncompressedSourceCache.purge();
|
||||
if (cx->caches.evalCache.initialized())
|
||||
cx->caches.evalCache.clear();
|
||||
|
||||
if (!rt->hasActiveCompilations())
|
||||
rt->parseMapPool(lock).purgeAll();
|
||||
@ -5537,9 +5540,10 @@ GCRuntime::compactPhase(JS::gcreason::Reason reason, SliceBudget& sliceBudget,
|
||||
break;
|
||||
}
|
||||
|
||||
// Clear runtime caches that can contain cell pointers.
|
||||
rt->newObjectCache.purge();
|
||||
rt->nativeIterCache.purge();
|
||||
// Clear caches that can contain cell pointers.
|
||||
JSContext* cx = rt->contextFromMainThread();
|
||||
cx->caches.newObjectCache.purge();
|
||||
cx->caches.nativeIterCache.purge();
|
||||
|
||||
#ifdef DEBUG
|
||||
CheckHashTablesAfterMovingGC(rt);
|
||||
|
@ -842,7 +842,7 @@ js::GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleOb
|
||||
if (flags == JSITER_ENUMERATE) {
|
||||
// Check to see if this is the same as the most recent object which was
|
||||
// iterated over.
|
||||
PropertyIteratorObject* last = cx->runtime()->nativeIterCache.last;
|
||||
PropertyIteratorObject* last = cx->caches.nativeIterCache.last;
|
||||
if (last) {
|
||||
NativeIterator* lastni = last->getNativeIterator();
|
||||
if (!(lastni->flags & (JSITER_ACTIVE|JSITER_UNREUSABLE)) &&
|
||||
@ -882,7 +882,7 @@ js::GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleOb
|
||||
} while (pobj);
|
||||
}
|
||||
|
||||
PropertyIteratorObject* iterobj = cx->runtime()->nativeIterCache.get(key);
|
||||
PropertyIteratorObject* iterobj = cx->caches.nativeIterCache.get(key);
|
||||
if (iterobj) {
|
||||
NativeIterator* ni = iterobj->getNativeIterator();
|
||||
if (!(ni->flags & (JSITER_ACTIVE|JSITER_UNREUSABLE)) &&
|
||||
@ -896,7 +896,7 @@ js::GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleOb
|
||||
UpdateNativeIterator(ni, obj);
|
||||
RegisterEnumerator(cx, iterobj, ni);
|
||||
if (guards.length() == 2)
|
||||
cx->runtime()->nativeIterCache.last = iterobj;
|
||||
cx->caches.nativeIterCache.last = iterobj;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -927,10 +927,10 @@ js::GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleOb
|
||||
|
||||
/* Cache the iterator object if possible. */
|
||||
if (guards.length())
|
||||
cx->runtime()->nativeIterCache.set(key, iterobj);
|
||||
cx->caches.nativeIterCache.set(key, iterobj);
|
||||
|
||||
if (guards.length() == 2)
|
||||
cx->runtime()->nativeIterCache.last = iterobj;
|
||||
cx->caches.nativeIterCache.last = iterobj;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -157,7 +157,7 @@ js::math_acos(JSContext* cx, unsigned argc, Value* vp)
|
||||
if (!ToNumber(cx, args[0], &x))
|
||||
return false;
|
||||
|
||||
MathCache* mathCache = cx->runtime()->getMathCache(cx);
|
||||
MathCache* mathCache = cx->caches.getMathCache(cx);
|
||||
if (!mathCache)
|
||||
return false;
|
||||
|
||||
@ -192,7 +192,7 @@ js::math_asin(JSContext* cx, unsigned argc, Value* vp)
|
||||
if (!ToNumber(cx, args[0], &x))
|
||||
return false;
|
||||
|
||||
MathCache* mathCache = cx->runtime()->getMathCache(cx);
|
||||
MathCache* mathCache = cx->caches.getMathCache(cx);
|
||||
if (!mathCache)
|
||||
return false;
|
||||
|
||||
@ -227,7 +227,7 @@ js::math_atan(JSContext* cx, unsigned argc, Value* vp)
|
||||
if (!ToNumber(cx, args[0], &x))
|
||||
return false;
|
||||
|
||||
MathCache* mathCache = cx->runtime()->getMathCache(cx);
|
||||
MathCache* mathCache = cx->caches.getMathCache(cx);
|
||||
if (!mathCache)
|
||||
return false;
|
||||
|
||||
@ -346,7 +346,7 @@ js::math_cos(JSContext* cx, unsigned argc, Value* vp)
|
||||
if (!ToNumber(cx, args[0], &x))
|
||||
return false;
|
||||
|
||||
MathCache* mathCache = cx->runtime()->getMathCache(cx);
|
||||
MathCache* mathCache = cx->caches.getMathCache(cx);
|
||||
if (!mathCache)
|
||||
return false;
|
||||
|
||||
@ -381,7 +381,7 @@ js::math_exp(JSContext* cx, unsigned argc, Value* vp)
|
||||
if (!ToNumber(cx, args[0], &x))
|
||||
return false;
|
||||
|
||||
MathCache* mathCache = cx->runtime()->getMathCache(cx);
|
||||
MathCache* mathCache = cx->caches.getMathCache(cx);
|
||||
if (!mathCache)
|
||||
return false;
|
||||
|
||||
@ -499,7 +499,7 @@ js::math_log_handle(JSContext* cx, HandleValue val, MutableHandleValue res)
|
||||
if (!ToNumber(cx, val, &in))
|
||||
return false;
|
||||
|
||||
MathCache* mathCache = cx->runtime()->getMathCache(cx);
|
||||
MathCache* mathCache = cx->caches.getMathCache(cx);
|
||||
if (!mathCache)
|
||||
return false;
|
||||
|
||||
@ -827,7 +827,7 @@ js::math_sin_handle(JSContext* cx, HandleValue val, MutableHandleValue res)
|
||||
if (!ToNumber(cx, val, &in))
|
||||
return false;
|
||||
|
||||
MathCache* mathCache = cx->runtime()->getMathCache(cx);
|
||||
MathCache* mathCache = cx->caches.getMathCache(cx);
|
||||
if (!mathCache)
|
||||
return false;
|
||||
|
||||
@ -890,7 +890,7 @@ js::math_sqrt_handle(JSContext* cx, HandleValue number, MutableHandleValue resul
|
||||
if (!ToNumber(cx, number, &x))
|
||||
return false;
|
||||
|
||||
MathCache* mathCache = cx->runtime()->getMathCache(cx);
|
||||
MathCache* mathCache = cx->caches.getMathCache(cx);
|
||||
if (!mathCache)
|
||||
return false;
|
||||
|
||||
@ -938,7 +938,7 @@ js::math_tan(JSContext* cx, unsigned argc, Value* vp)
|
||||
if (!ToNumber(cx, args[0], &x))
|
||||
return false;
|
||||
|
||||
MathCache* mathCache = cx->runtime()->getMathCache(cx);
|
||||
MathCache* mathCache = cx->caches.getMathCache(cx);
|
||||
if (!mathCache)
|
||||
return false;
|
||||
|
||||
@ -962,7 +962,7 @@ static bool math_function(JSContext* cx, unsigned argc, Value* vp)
|
||||
if (!ToNumber(cx, args[0], &x))
|
||||
return false;
|
||||
|
||||
MathCache* mathCache = cx->runtime()->getMathCache(cx);
|
||||
MathCache* mathCache = cx->caches.getMathCache(cx);
|
||||
if (!mathCache)
|
||||
return false;
|
||||
double z = F(mathCache, x);
|
||||
|
@ -62,10 +62,10 @@
|
||||
|
||||
#include "vm/ArrayObject-inl.h"
|
||||
#include "vm/BooleanObject-inl.h"
|
||||
#include "vm/Caches-inl.h"
|
||||
#include "vm/Interpreter-inl.h"
|
||||
#include "vm/NativeObject-inl.h"
|
||||
#include "vm/NumberObject-inl.h"
|
||||
#include "vm/Runtime-inl.h"
|
||||
#include "vm/Shape-inl.h"
|
||||
#include "vm/StringObject-inl.h"
|
||||
|
||||
@ -715,8 +715,7 @@ js::NewObjectWithGivenTaggedProto(ExclusiveContext* cxArg, const Class* clasp,
|
||||
bool isCachable = NewObjectWithTaggedProtoIsCachable(cxArg, proto, newKind, clasp);
|
||||
if (isCachable) {
|
||||
JSContext* cx = cxArg->asJSContext();
|
||||
JSRuntime* rt = cx->runtime();
|
||||
NewObjectCache& cache = rt->newObjectCache;
|
||||
NewObjectCache& cache = cx->caches.newObjectCache;
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
if (cache.lookupProto(clasp, proto.toObject(), allocKind, &entry)) {
|
||||
JSObject* obj = cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, clasp));
|
||||
@ -734,7 +733,7 @@ js::NewObjectWithGivenTaggedProto(ExclusiveContext* cxArg, const Class* clasp,
|
||||
return nullptr;
|
||||
|
||||
if (isCachable && !obj->as<NativeObject>().hasDynamicSlots()) {
|
||||
NewObjectCache& cache = cxArg->asJSContext()->runtime()->newObjectCache;
|
||||
NewObjectCache& cache = cxArg->asJSContext()->caches.newObjectCache;
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
cache.lookupProto(clasp, proto.toObject(), allocKind, &entry);
|
||||
cache.fillProto(entry, clasp, proto, allocKind, &obj->as<NativeObject>());
|
||||
@ -769,8 +768,7 @@ js::NewObjectWithClassProtoCommon(ExclusiveContext* cxArg, const Class* clasp,
|
||||
bool isCachable = NewObjectIsCachable(cxArg, newKind, clasp);
|
||||
if (isCachable) {
|
||||
JSContext* cx = cxArg->asJSContext();
|
||||
JSRuntime* rt = cx->runtime();
|
||||
NewObjectCache& cache = rt->newObjectCache;
|
||||
NewObjectCache& cache = cx->caches.newObjectCache;
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
if (cache.lookupGlobal(clasp, global, allocKind, &entry)) {
|
||||
JSObject* obj = cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, clasp));
|
||||
@ -801,7 +799,7 @@ js::NewObjectWithClassProtoCommon(ExclusiveContext* cxArg, const Class* clasp,
|
||||
return nullptr;
|
||||
|
||||
if (isCachable && !obj->as<NativeObject>().hasDynamicSlots()) {
|
||||
NewObjectCache& cache = cxArg->asJSContext()->runtime()->newObjectCache;
|
||||
NewObjectCache& cache = cxArg->asJSContext()->caches.newObjectCache;
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
cache.lookupGlobal(clasp, global, allocKind, &entry);
|
||||
cache.fillGlobal(entry, clasp, global, allocKind,
|
||||
@ -836,7 +834,7 @@ js::NewObjectWithGroupCommon(ExclusiveContext* cx, HandleObjectGroup group,
|
||||
|
||||
bool isCachable = NewObjectWithGroupIsCachable(cx, group, newKind);
|
||||
if (isCachable) {
|
||||
NewObjectCache& cache = cx->asJSContext()->runtime()->newObjectCache;
|
||||
NewObjectCache& cache = cx->asJSContext()->caches.newObjectCache;
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
if (cache.lookupGroup(group, allocKind, &entry)) {
|
||||
JSObject* obj = cache.newObjectFromHit(cx->asJSContext(), entry,
|
||||
@ -851,7 +849,7 @@ js::NewObjectWithGroupCommon(ExclusiveContext* cx, HandleObjectGroup group,
|
||||
return nullptr;
|
||||
|
||||
if (isCachable && !obj->as<NativeObject>().hasDynamicSlots()) {
|
||||
NewObjectCache& cache = cx->asJSContext()->runtime()->newObjectCache;
|
||||
NewObjectCache& cache = cx->asJSContext()->caches.newObjectCache;
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
cache.lookupGroup(group, allocKind, &entry);
|
||||
cache.fillGroup(entry, group, allocKind, &obj->as<NativeObject>());
|
||||
|
@ -891,7 +891,7 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
||||
|
||||
case JOF_SCOPECOORD: {
|
||||
RootedValue v(cx,
|
||||
StringValue(ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc)));
|
||||
StringValue(ScopeCoordinateName(cx->caches.scopeCoordinateNameCache, script, pc)));
|
||||
JSAutoByteString bytes;
|
||||
if (!ToDisassemblySource(cx, v, &bytes))
|
||||
return 0;
|
||||
@ -1143,7 +1143,7 @@ ExpressionDecompiler::decompilePC(jsbytecode* pc)
|
||||
return write("(intermediate value)");
|
||||
}
|
||||
case JSOP_GETALIASEDVAR: {
|
||||
JSAtom* atom = ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc);
|
||||
JSAtom* atom = ScopeCoordinateName(cx->caches.scopeCoordinateNameCache, script, pc);
|
||||
MOZ_ASSERT(atom);
|
||||
return write(atom);
|
||||
}
|
||||
|
@ -1879,7 +1879,7 @@ ScriptSource::chars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holde
|
||||
}
|
||||
|
||||
ReturnType match(Compressed& c) {
|
||||
if (const char16_t* decompressed = cx->runtime()->uncompressedSourceCache.lookup(&ss, holder))
|
||||
if (const char16_t* decompressed = cx->caches.uncompressedSourceCache.lookup(&ss, holder))
|
||||
return decompressed;
|
||||
|
||||
const size_t lengthWithNull = ss.length() + 1;
|
||||
@ -1917,7 +1917,7 @@ ScriptSource::chars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holde
|
||||
}
|
||||
|
||||
ReturnType ret = decompressed.get();
|
||||
if (!cx->runtime()->uncompressedSourceCache.put(&ss, Move(decompressed), holder)) {
|
||||
if (!cx->caches.uncompressedSourceCache.put(&ss, Move(decompressed), holder)) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
@ -3158,7 +3158,7 @@ JSScript::finalize(FreeOp* fop)
|
||||
fop->free_(data);
|
||||
}
|
||||
|
||||
fop->runtime()->lazyScriptCache.remove(this);
|
||||
fop->runtime()->contextFromMainThread()->caches.lazyScriptCache.remove(this);
|
||||
|
||||
// In most cases, our LazyScript's script pointer will reference this
|
||||
// script, and thus be nulled out by normal weakref processing. However, if
|
||||
@ -3237,7 +3237,7 @@ js::GetSrcNote(GSNCache& cache, JSScript* script, jsbytecode* pc)
|
||||
jssrcnote*
|
||||
js::GetSrcNote(JSContext* cx, JSScript* script, jsbytecode* pc)
|
||||
{
|
||||
return GetSrcNote(cx->runtime()->gsnCache, script, pc);
|
||||
return GetSrcNote(cx->caches.gsnCache, script, pc);
|
||||
}
|
||||
|
||||
unsigned
|
||||
|
@ -316,6 +316,7 @@ UNIFIED_SOURCES += [
|
||||
'proxy/Wrapper.cpp',
|
||||
'vm/ArgumentsObject.cpp',
|
||||
'vm/ArrayBufferObject.cpp',
|
||||
'vm/Caches.cpp',
|
||||
'vm/CallNonGenericMethod.cpp',
|
||||
'vm/CharacterEncoding.cpp',
|
||||
'vm/CodeCoverage.cpp',
|
||||
|
@ -4,10 +4,10 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef vm_Runtime_inl_h
|
||||
#define vm_Runtime_inl_h
|
||||
#ifndef vm_Caches_inl_h
|
||||
#define vm_Caches_inl_h
|
||||
|
||||
#include "vm/Runtime.h"
|
||||
#include "vm/Caches.h"
|
||||
|
||||
#include "jscompartment.h"
|
||||
|
||||
@ -79,4 +79,4 @@ NewObjectCache::newObjectFromHit(JSContext* cx, EntryIndex entryIndex, gc::Initi
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* vm_Runtime_inl_h */
|
||||
#endif /* vm_Caches_inl_h */
|
52
js/src/vm/Caches.cpp
Normal file
52
js/src/vm/Caches.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "vm/Caches-inl.h"
|
||||
|
||||
#include "mozilla/PodOperations.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
using mozilla::PodZero;
|
||||
|
||||
MathCache*
|
||||
ContextCaches::createMathCache(JSContext* cx)
|
||||
{
|
||||
MOZ_ASSERT(!mathCache_);
|
||||
|
||||
UniquePtr<MathCache> newMathCache(js_new<MathCache>());
|
||||
if (!newMathCache) {
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mathCache_ = Move(newMathCache);
|
||||
return mathCache_.get();
|
||||
}
|
||||
|
||||
bool
|
||||
ContextCaches::init()
|
||||
{
|
||||
if (!evalCache.init())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
NewObjectCache::clearNurseryObjects(JSRuntime* rt)
|
||||
{
|
||||
for (unsigned i = 0; i < mozilla::ArrayLength(entries); ++i) {
|
||||
Entry& e = entries[i];
|
||||
NativeObject* obj = reinterpret_cast<NativeObject*>(&e.templateObject);
|
||||
if (IsInsideNursery(e.key) ||
|
||||
rt->gc.nursery.isInside(obj->slots_) ||
|
||||
rt->gc.nursery.isInside(obj->elements_))
|
||||
{
|
||||
PodZero(&e);
|
||||
}
|
||||
}
|
||||
}
|
312
js/src/vm/Caches.h
Normal file
312
js/src/vm/Caches.h
Normal file
@ -0,0 +1,312 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef vm_Caches_h
|
||||
#define vm_Caches_h
|
||||
|
||||
#include "jsatom.h"
|
||||
#include "jsbytecode.h"
|
||||
#include "jsobj.h"
|
||||
#include "jsscript.h"
|
||||
|
||||
#include "ds/FixedSizeHash.h"
|
||||
#include "frontend/SourceNotes.h"
|
||||
#include "gc/Tracer.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/UniquePtr.h"
|
||||
#include "vm/NativeObject.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* GetSrcNote cache to avoid O(n^2) growth in finding a source note for a
|
||||
* given pc in a script. We use the script->code pointer to tag the cache,
|
||||
* instead of the script address itself, so that source notes are always found
|
||||
* by offset from the bytecode with which they were generated.
|
||||
*/
|
||||
struct GSNCache {
|
||||
typedef HashMap<jsbytecode*,
|
||||
jssrcnote*,
|
||||
PointerHasher<jsbytecode*, 0>,
|
||||
SystemAllocPolicy> Map;
|
||||
|
||||
jsbytecode* code;
|
||||
Map map;
|
||||
|
||||
GSNCache() : code(nullptr) { }
|
||||
|
||||
void purge();
|
||||
};
|
||||
|
||||
/*
|
||||
* ScopeCoordinateName cache to avoid O(n^2) growth in finding the name
|
||||
* associated with a given aliasedvar operation.
|
||||
*/
|
||||
struct ScopeCoordinateNameCache {
|
||||
typedef HashMap<uint32_t,
|
||||
jsid,
|
||||
DefaultHasher<uint32_t>,
|
||||
SystemAllocPolicy> Map;
|
||||
|
||||
Shape* shape;
|
||||
Map map;
|
||||
|
||||
ScopeCoordinateNameCache() : shape(nullptr) {}
|
||||
void purge();
|
||||
};
|
||||
|
||||
struct EvalCacheEntry
|
||||
{
|
||||
JSLinearString* str;
|
||||
JSScript* script;
|
||||
JSScript* callerScript;
|
||||
jsbytecode* pc;
|
||||
};
|
||||
|
||||
struct EvalCacheLookup
|
||||
{
|
||||
explicit EvalCacheLookup(JSContext* cx) : str(cx), callerScript(cx) {}
|
||||
RootedLinearString str;
|
||||
RootedScript callerScript;
|
||||
JSVersion version;
|
||||
jsbytecode* pc;
|
||||
};
|
||||
|
||||
struct EvalCacheHashPolicy
|
||||
{
|
||||
typedef EvalCacheLookup Lookup;
|
||||
|
||||
static HashNumber hash(const Lookup& l);
|
||||
static bool match(const EvalCacheEntry& entry, const EvalCacheLookup& l);
|
||||
};
|
||||
|
||||
typedef HashSet<EvalCacheEntry, EvalCacheHashPolicy, SystemAllocPolicy> EvalCache;
|
||||
|
||||
struct LazyScriptHashPolicy
|
||||
{
|
||||
struct Lookup {
|
||||
JSContext* cx;
|
||||
LazyScript* lazy;
|
||||
|
||||
Lookup(JSContext* cx, LazyScript* lazy)
|
||||
: cx(cx), lazy(lazy)
|
||||
{}
|
||||
};
|
||||
|
||||
static const size_t NumHashes = 3;
|
||||
|
||||
static void hash(const Lookup& lookup, HashNumber hashes[NumHashes]);
|
||||
static bool match(JSScript* script, const Lookup& lookup);
|
||||
|
||||
// Alternate methods for use when removing scripts from the hash without an
|
||||
// explicit LazyScript lookup.
|
||||
static void hash(JSScript* script, HashNumber hashes[NumHashes]);
|
||||
static bool match(JSScript* script, JSScript* lookup) { return script == lookup; }
|
||||
|
||||
static void clear(JSScript** pscript) { *pscript = nullptr; }
|
||||
static bool isCleared(JSScript* script) { return !script; }
|
||||
};
|
||||
|
||||
typedef FixedSizeHashSet<JSScript*, LazyScriptHashPolicy, 769> LazyScriptCache;
|
||||
|
||||
class PropertyIteratorObject;
|
||||
|
||||
class NativeIterCache
|
||||
{
|
||||
static const size_t SIZE = size_t(1) << 8;
|
||||
|
||||
/* Cached native iterators. */
|
||||
PropertyIteratorObject* data[SIZE];
|
||||
|
||||
static size_t getIndex(uint32_t key) {
|
||||
return size_t(key) % SIZE;
|
||||
}
|
||||
|
||||
public:
|
||||
/* Native iterator most recently started. */
|
||||
PropertyIteratorObject* last;
|
||||
|
||||
NativeIterCache()
|
||||
: last(nullptr)
|
||||
{
|
||||
mozilla::PodArrayZero(data);
|
||||
}
|
||||
|
||||
void purge() {
|
||||
last = nullptr;
|
||||
mozilla::PodArrayZero(data);
|
||||
}
|
||||
|
||||
PropertyIteratorObject* get(uint32_t key) const {
|
||||
return data[getIndex(key)];
|
||||
}
|
||||
|
||||
void set(uint32_t key, PropertyIteratorObject* iterobj) {
|
||||
data[getIndex(key)] = iterobj;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Cache for speeding up repetitive creation of objects in the VM.
|
||||
* When an object is created which matches the criteria in the 'key' section
|
||||
* below, an entry is filled with the resulting object.
|
||||
*/
|
||||
class NewObjectCache
|
||||
{
|
||||
/* Statically asserted to be equal to sizeof(JSObject_Slots16) */
|
||||
static const unsigned MAX_OBJ_SIZE = 4 * sizeof(void*) + 16 * sizeof(Value);
|
||||
|
||||
static void staticAsserts() {
|
||||
JS_STATIC_ASSERT(NewObjectCache::MAX_OBJ_SIZE == sizeof(JSObject_Slots16));
|
||||
JS_STATIC_ASSERT(gc::AllocKind::OBJECT_LAST == gc::AllocKind::OBJECT16_BACKGROUND);
|
||||
}
|
||||
|
||||
struct Entry
|
||||
{
|
||||
/* Class of the constructed object. */
|
||||
const Class* clasp;
|
||||
|
||||
/*
|
||||
* Key with one of three possible values:
|
||||
*
|
||||
* - Global for the object. The object must have a standard class for
|
||||
* which the global's prototype can be determined, and the object's
|
||||
* parent will be the global.
|
||||
*
|
||||
* - Prototype for the object (cannot be global). The object's parent
|
||||
* will be the prototype's parent.
|
||||
*
|
||||
* - Type for the object. The object's parent will be the type's
|
||||
* prototype's parent.
|
||||
*/
|
||||
gc::Cell* key;
|
||||
|
||||
/* Allocation kind for the constructed object. */
|
||||
gc::AllocKind kind;
|
||||
|
||||
/* Number of bytes to copy from the template object. */
|
||||
uint32_t nbytes;
|
||||
|
||||
/*
|
||||
* Template object to copy from, with the initial values of fields,
|
||||
* fixed slots (undefined) and private data (nullptr).
|
||||
*/
|
||||
char templateObject[MAX_OBJ_SIZE];
|
||||
};
|
||||
|
||||
Entry entries[41]; // TODO: reconsider size
|
||||
|
||||
public:
|
||||
|
||||
typedef int EntryIndex;
|
||||
|
||||
NewObjectCache() { mozilla::PodZero(this); }
|
||||
void purge() { mozilla::PodZero(this); }
|
||||
|
||||
/* Remove any cached items keyed on moved objects. */
|
||||
void clearNurseryObjects(JSRuntime* rt);
|
||||
|
||||
/*
|
||||
* Get the entry index for the given lookup, return whether there was a hit
|
||||
* on an existing entry.
|
||||
*/
|
||||
inline bool lookupProto(const Class* clasp, JSObject* proto, gc::AllocKind kind, EntryIndex* pentry);
|
||||
inline bool lookupGlobal(const Class* clasp, js::GlobalObject* global, gc::AllocKind kind,
|
||||
EntryIndex* pentry);
|
||||
|
||||
bool lookupGroup(js::ObjectGroup* group, gc::AllocKind kind, EntryIndex* pentry) {
|
||||
return lookup(group->clasp(), group, kind, pentry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a new object from a cache hit produced by a lookup method, or
|
||||
* nullptr if returning the object could possibly trigger GC (does not
|
||||
* indicate failure).
|
||||
*/
|
||||
inline NativeObject* newObjectFromHit(JSContext* cx, EntryIndex entry, js::gc::InitialHeap heap);
|
||||
|
||||
/* Fill an entry after a cache miss. */
|
||||
void fillProto(EntryIndex entry, const Class* clasp, js::TaggedProto proto,
|
||||
gc::AllocKind kind, NativeObject* obj);
|
||||
|
||||
inline void fillGlobal(EntryIndex entry, const Class* clasp, js::GlobalObject* global,
|
||||
gc::AllocKind kind, NativeObject* obj);
|
||||
|
||||
void fillGroup(EntryIndex entry, js::ObjectGroup* group, gc::AllocKind kind,
|
||||
NativeObject* obj)
|
||||
{
|
||||
MOZ_ASSERT(obj->group() == group);
|
||||
return fill(entry, group->clasp(), group, kind, obj);
|
||||
}
|
||||
|
||||
/* Invalidate any entries which might produce an object with shape/proto. */
|
||||
void invalidateEntriesForShape(JSContext* cx, HandleShape shape, HandleObject proto);
|
||||
|
||||
private:
|
||||
EntryIndex makeIndex(const Class* clasp, gc::Cell* key, gc::AllocKind kind) {
|
||||
uintptr_t hash = (uintptr_t(clasp) ^ uintptr_t(key)) + size_t(kind);
|
||||
return hash % mozilla::ArrayLength(entries);
|
||||
}
|
||||
|
||||
bool lookup(const Class* clasp, gc::Cell* key, gc::AllocKind kind, EntryIndex* pentry) {
|
||||
*pentry = makeIndex(clasp, key, kind);
|
||||
Entry* entry = &entries[*pentry];
|
||||
|
||||
/* N.B. Lookups with the same clasp/key but different kinds map to different entries. */
|
||||
return entry->clasp == clasp && entry->key == key;
|
||||
}
|
||||
|
||||
void fill(EntryIndex entry_, const Class* clasp, gc::Cell* key, gc::AllocKind kind,
|
||||
NativeObject* obj) {
|
||||
MOZ_ASSERT(unsigned(entry_) < mozilla::ArrayLength(entries));
|
||||
MOZ_ASSERT(entry_ == makeIndex(clasp, key, kind));
|
||||
Entry* entry = &entries[entry_];
|
||||
|
||||
entry->clasp = clasp;
|
||||
entry->key = key;
|
||||
entry->kind = kind;
|
||||
|
||||
entry->nbytes = gc::Arena::thingSize(kind);
|
||||
js_memcpy(&entry->templateObject, obj, entry->nbytes);
|
||||
}
|
||||
|
||||
static void copyCachedToObject(NativeObject* dst, NativeObject* src, gc::AllocKind kind) {
|
||||
js_memcpy(dst, src, gc::Arena::thingSize(kind));
|
||||
Shape::writeBarrierPost(&dst->shape_, nullptr, dst->shape_);
|
||||
ObjectGroup::writeBarrierPost(&dst->group_, nullptr, dst->group_);
|
||||
}
|
||||
};
|
||||
|
||||
class MathCache;
|
||||
|
||||
class ContextCaches
|
||||
{
|
||||
UniquePtr<js::MathCache> mathCache_;
|
||||
|
||||
js::MathCache* createMathCache(JSContext* cx);
|
||||
|
||||
public:
|
||||
js::GSNCache gsnCache;
|
||||
js::ScopeCoordinateNameCache scopeCoordinateNameCache;
|
||||
js::NewObjectCache newObjectCache;
|
||||
js::NativeIterCache nativeIterCache;
|
||||
js::UncompressedSourceCache uncompressedSourceCache;
|
||||
js::EvalCache evalCache;
|
||||
js::LazyScriptCache lazyScriptCache;
|
||||
|
||||
bool init();
|
||||
|
||||
js::MathCache* getMathCache(JSContext* cx) {
|
||||
return mathCache_ ? mathCache_.get() : createMathCache(cx);
|
||||
}
|
||||
js::MathCache* maybeGetMathCache() {
|
||||
return mathCache_.get();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* vm_Caches_h */
|
@ -247,7 +247,7 @@ SetAliasedVarOperation(JSContext* cx, JSScript* script, jsbytecode* pc,
|
||||
// Avoid computing the name if no type updates are needed, as this may be
|
||||
// expensive on scopes with large numbers of variables.
|
||||
PropertyName* name = obj.isSingleton()
|
||||
? ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc)
|
||||
? ScopeCoordinateName(cx->caches.scopeCoordinateNameCache, script, pc)
|
||||
: nullptr;
|
||||
|
||||
obj.setAliasedVar(cx, sc, name, val);
|
||||
|
@ -3222,7 +3222,7 @@ CASE(JSOP_GETALIASEDVAR)
|
||||
#ifdef DEBUG
|
||||
// Only the .this slot can hold the TDZ MagicValue.
|
||||
if (IsUninitializedLexical(val)) {
|
||||
PropertyName* name = ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache,
|
||||
PropertyName* name = ScopeCoordinateName(cx->caches.scopeCoordinateNameCache,
|
||||
script, REGS.pc);
|
||||
MOZ_ASSERT(name == cx->names().dotThis);
|
||||
JSOp next = JSOp(*GetNextPc(REGS.pc));
|
||||
@ -4944,7 +4944,7 @@ js::ReportRuntimeLexicalError(JSContext* cx, unsigned errorNumber,
|
||||
name = script->getName(pc);
|
||||
} else {
|
||||
MOZ_ASSERT(IsAliasedVarOp(op));
|
||||
name = ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc);
|
||||
name = ScopeCoordinateName(cx->caches.scopeCoordinateNameCache, script, pc);
|
||||
}
|
||||
|
||||
ReportRuntimeLexicalError(cx, errorNumber, name);
|
||||
|
@ -4,8 +4,6 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "vm/Runtime-inl.h"
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
@ -226,7 +224,6 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
||||
decimalSeparator(0),
|
||||
numGrouping(0),
|
||||
#endif
|
||||
mathCache_(nullptr),
|
||||
activeCompilations_(0),
|
||||
keepAtoms_(0),
|
||||
trustedPrincipals_(nullptr),
|
||||
@ -337,9 +334,6 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
|
||||
if (!scriptDataTable_.init())
|
||||
return false;
|
||||
|
||||
if (!evalCache.init())
|
||||
return false;
|
||||
|
||||
/* The garbage collector depends on everything before this point being initialized. */
|
||||
gcInitialized = true;
|
||||
|
||||
@ -460,7 +454,6 @@ JSRuntime::destroyRuntime()
|
||||
atomsCompartment_ = nullptr;
|
||||
|
||||
js_free(defaultLocale);
|
||||
js_delete(mathCache_);
|
||||
js_delete(jitRuntime_);
|
||||
|
||||
js_delete(ionPcScriptCache);
|
||||
@ -496,21 +489,6 @@ JSRuntime::setTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback
|
||||
rt->telemetryCallback = callback;
|
||||
}
|
||||
|
||||
void
|
||||
NewObjectCache::clearNurseryObjects(JSRuntime* rt)
|
||||
{
|
||||
for (unsigned i = 0; i < mozilla::ArrayLength(entries); ++i) {
|
||||
Entry& e = entries[i];
|
||||
NativeObject* obj = reinterpret_cast<NativeObject*>(&e.templateObject);
|
||||
if (IsInsideNursery(e.key) ||
|
||||
rt->gc.nursery.isInside(obj->slots_) ||
|
||||
rt->gc.nursery.isInside(obj->elements_))
|
||||
{
|
||||
PodZero(&e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* rtSizes)
|
||||
{
|
||||
@ -520,7 +498,8 @@ JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Runtim
|
||||
// For now, measure the size of the derived class (JSContext).
|
||||
// TODO (bug 1281529): make memory reporting reflect the new
|
||||
// JSContext/JSRuntime world better.
|
||||
rtSizes->object += mallocSizeOf(unsafeContextFromAnyThread());
|
||||
JSContext* cx = unsafeContextFromAnyThread();
|
||||
rtSizes->object += mallocSizeOf(cx);
|
||||
|
||||
rtSizes->atomsTable += atoms(lock).sizeOfIncludingThis(mallocSizeOf);
|
||||
|
||||
@ -530,20 +509,23 @@ JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Runtim
|
||||
rtSizes->atomsTable += permanentAtoms->sizeOfIncludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
rtSizes->contexts += unsafeContextFromAnyThread()->sizeOfExcludingThis(mallocSizeOf);
|
||||
rtSizes->contexts += cx->sizeOfExcludingThis(mallocSizeOf);
|
||||
|
||||
rtSizes->temporary += tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
|
||||
|
||||
rtSizes->interpreterStack += interpreterStack_.sizeOfExcludingThis(mallocSizeOf);
|
||||
|
||||
rtSizes->mathCache += mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0;
|
||||
if (MathCache* cache = cx->caches.maybeGetMathCache())
|
||||
rtSizes->mathCache += cache->sizeOfIncludingThis(mallocSizeOf);
|
||||
|
||||
if (sharedImmutableStrings_) {
|
||||
rtSizes->sharedImmutableStringsCache +=
|
||||
sharedImmutableStrings_->sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
rtSizes->uncompressedSourceCache += uncompressedSourceCache.sizeOfExcludingThis(mallocSizeOf);
|
||||
rtSizes->uncompressedSourceCache +=
|
||||
cx->caches.uncompressedSourceCache.sizeOfExcludingThis(mallocSizeOf);
|
||||
|
||||
|
||||
rtSizes->scriptData += scriptDataTable(lock).sizeOfExcludingThis(mallocSizeOf);
|
||||
for (ScriptDataTable::Range r = scriptDataTable(lock).all(); !r.empty(); r.popFront())
|
||||
@ -678,22 +660,6 @@ JSRuntime::handleInterrupt(JSContext* cx)
|
||||
return true;
|
||||
}
|
||||
|
||||
MathCache*
|
||||
JSRuntime::createMathCache(JSContext* cx)
|
||||
{
|
||||
MOZ_ASSERT(!mathCache_);
|
||||
MOZ_ASSERT(cx->runtime() == this);
|
||||
|
||||
MathCache* newMathCache = js_new<MathCache>();
|
||||
if (!newMathCache) {
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mathCache_ = newMathCache;
|
||||
return mathCache_;
|
||||
}
|
||||
|
||||
bool
|
||||
JSRuntime::setDefaultLocale(const char* locale)
|
||||
{
|
||||
|
@ -90,7 +90,6 @@ ReportOverRecursed(ExclusiveContext* cx);
|
||||
|
||||
class Activation;
|
||||
class ActivationIterator;
|
||||
class MathCache;
|
||||
class WasmActivation;
|
||||
|
||||
namespace jit {
|
||||
@ -111,267 +110,6 @@ namespace wasm {
|
||||
class Module;
|
||||
} // namespace wasm
|
||||
|
||||
/*
|
||||
* GetSrcNote cache to avoid O(n^2) growth in finding a source note for a
|
||||
* given pc in a script. We use the script->code pointer to tag the cache,
|
||||
* instead of the script address itself, so that source notes are always found
|
||||
* by offset from the bytecode with which they were generated.
|
||||
*/
|
||||
struct GSNCache {
|
||||
typedef HashMap<jsbytecode*,
|
||||
jssrcnote*,
|
||||
PointerHasher<jsbytecode*, 0>,
|
||||
SystemAllocPolicy> Map;
|
||||
|
||||
jsbytecode* code;
|
||||
Map map;
|
||||
|
||||
GSNCache() : code(nullptr) { }
|
||||
|
||||
void purge();
|
||||
};
|
||||
|
||||
/*
|
||||
* ScopeCoordinateName cache to avoid O(n^2) growth in finding the name
|
||||
* associated with a given aliasedvar operation.
|
||||
*/
|
||||
struct ScopeCoordinateNameCache {
|
||||
typedef HashMap<uint32_t,
|
||||
jsid,
|
||||
DefaultHasher<uint32_t>,
|
||||
SystemAllocPolicy> Map;
|
||||
|
||||
Shape* shape;
|
||||
Map map;
|
||||
|
||||
ScopeCoordinateNameCache() : shape(nullptr) {}
|
||||
void purge();
|
||||
};
|
||||
|
||||
using ScriptAndCountsVector = GCVector<ScriptAndCounts, 0, SystemAllocPolicy>;
|
||||
|
||||
struct EvalCacheEntry
|
||||
{
|
||||
JSLinearString* str;
|
||||
JSScript* script;
|
||||
JSScript* callerScript;
|
||||
jsbytecode* pc;
|
||||
};
|
||||
|
||||
struct EvalCacheLookup
|
||||
{
|
||||
explicit EvalCacheLookup(JSContext* cx) : str(cx), callerScript(cx) {}
|
||||
RootedLinearString str;
|
||||
RootedScript callerScript;
|
||||
JSVersion version;
|
||||
jsbytecode* pc;
|
||||
};
|
||||
|
||||
struct EvalCacheHashPolicy
|
||||
{
|
||||
typedef EvalCacheLookup Lookup;
|
||||
|
||||
static HashNumber hash(const Lookup& l);
|
||||
static bool match(const EvalCacheEntry& entry, const EvalCacheLookup& l);
|
||||
};
|
||||
|
||||
typedef HashSet<EvalCacheEntry, EvalCacheHashPolicy, SystemAllocPolicy> EvalCache;
|
||||
|
||||
struct LazyScriptHashPolicy
|
||||
{
|
||||
struct Lookup {
|
||||
JSContext* cx;
|
||||
LazyScript* lazy;
|
||||
|
||||
Lookup(JSContext* cx, LazyScript* lazy)
|
||||
: cx(cx), lazy(lazy)
|
||||
{}
|
||||
};
|
||||
|
||||
static const size_t NumHashes = 3;
|
||||
|
||||
static void hash(const Lookup& lookup, HashNumber hashes[NumHashes]);
|
||||
static bool match(JSScript* script, const Lookup& lookup);
|
||||
|
||||
// Alternate methods for use when removing scripts from the hash without an
|
||||
// explicit LazyScript lookup.
|
||||
static void hash(JSScript* script, HashNumber hashes[NumHashes]);
|
||||
static bool match(JSScript* script, JSScript* lookup) { return script == lookup; }
|
||||
|
||||
static void clear(JSScript** pscript) { *pscript = nullptr; }
|
||||
static bool isCleared(JSScript* script) { return !script; }
|
||||
};
|
||||
|
||||
typedef FixedSizeHashSet<JSScript*, LazyScriptHashPolicy, 769> LazyScriptCache;
|
||||
|
||||
class PropertyIteratorObject;
|
||||
|
||||
class NativeIterCache
|
||||
{
|
||||
static const size_t SIZE = size_t(1) << 8;
|
||||
|
||||
/* Cached native iterators. */
|
||||
PropertyIteratorObject* data[SIZE];
|
||||
|
||||
static size_t getIndex(uint32_t key) {
|
||||
return size_t(key) % SIZE;
|
||||
}
|
||||
|
||||
public:
|
||||
/* Native iterator most recently started. */
|
||||
PropertyIteratorObject* last;
|
||||
|
||||
NativeIterCache()
|
||||
: last(nullptr)
|
||||
{
|
||||
mozilla::PodArrayZero(data);
|
||||
}
|
||||
|
||||
void purge() {
|
||||
last = nullptr;
|
||||
mozilla::PodArrayZero(data);
|
||||
}
|
||||
|
||||
PropertyIteratorObject* get(uint32_t key) const {
|
||||
return data[getIndex(key)];
|
||||
}
|
||||
|
||||
void set(uint32_t key, PropertyIteratorObject* iterobj) {
|
||||
data[getIndex(key)] = iterobj;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Cache for speeding up repetitive creation of objects in the VM.
|
||||
* When an object is created which matches the criteria in the 'key' section
|
||||
* below, an entry is filled with the resulting object.
|
||||
*/
|
||||
class NewObjectCache
|
||||
{
|
||||
/* Statically asserted to be equal to sizeof(JSObject_Slots16) */
|
||||
static const unsigned MAX_OBJ_SIZE = 4 * sizeof(void*) + 16 * sizeof(Value);
|
||||
|
||||
static void staticAsserts() {
|
||||
JS_STATIC_ASSERT(NewObjectCache::MAX_OBJ_SIZE == sizeof(JSObject_Slots16));
|
||||
JS_STATIC_ASSERT(gc::AllocKind::OBJECT_LAST == gc::AllocKind::OBJECT16_BACKGROUND);
|
||||
}
|
||||
|
||||
struct Entry
|
||||
{
|
||||
/* Class of the constructed object. */
|
||||
const Class* clasp;
|
||||
|
||||
/*
|
||||
* Key with one of three possible values:
|
||||
*
|
||||
* - Global for the object. The object must have a standard class for
|
||||
* which the global's prototype can be determined, and the object's
|
||||
* parent will be the global.
|
||||
*
|
||||
* - Prototype for the object (cannot be global). The object's parent
|
||||
* will be the prototype's parent.
|
||||
*
|
||||
* - Type for the object. The object's parent will be the type's
|
||||
* prototype's parent.
|
||||
*/
|
||||
gc::Cell* key;
|
||||
|
||||
/* Allocation kind for the constructed object. */
|
||||
gc::AllocKind kind;
|
||||
|
||||
/* Number of bytes to copy from the template object. */
|
||||
uint32_t nbytes;
|
||||
|
||||
/*
|
||||
* Template object to copy from, with the initial values of fields,
|
||||
* fixed slots (undefined) and private data (nullptr).
|
||||
*/
|
||||
char templateObject[MAX_OBJ_SIZE];
|
||||
};
|
||||
|
||||
Entry entries[41]; // TODO: reconsider size
|
||||
|
||||
public:
|
||||
|
||||
typedef int EntryIndex;
|
||||
|
||||
NewObjectCache() { mozilla::PodZero(this); }
|
||||
void purge() { mozilla::PodZero(this); }
|
||||
|
||||
/* Remove any cached items keyed on moved objects. */
|
||||
void clearNurseryObjects(JSRuntime* rt);
|
||||
|
||||
/*
|
||||
* Get the entry index for the given lookup, return whether there was a hit
|
||||
* on an existing entry.
|
||||
*/
|
||||
inline bool lookupProto(const Class* clasp, JSObject* proto, gc::AllocKind kind, EntryIndex* pentry);
|
||||
inline bool lookupGlobal(const Class* clasp, js::GlobalObject* global, gc::AllocKind kind,
|
||||
EntryIndex* pentry);
|
||||
|
||||
bool lookupGroup(js::ObjectGroup* group, gc::AllocKind kind, EntryIndex* pentry) {
|
||||
return lookup(group->clasp(), group, kind, pentry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a new object from a cache hit produced by a lookup method, or
|
||||
* nullptr if returning the object could possibly trigger GC (does not
|
||||
* indicate failure).
|
||||
*/
|
||||
inline NativeObject* newObjectFromHit(JSContext* cx, EntryIndex entry, js::gc::InitialHeap heap);
|
||||
|
||||
/* Fill an entry after a cache miss. */
|
||||
void fillProto(EntryIndex entry, const Class* clasp, js::TaggedProto proto,
|
||||
gc::AllocKind kind, NativeObject* obj);
|
||||
|
||||
inline void fillGlobal(EntryIndex entry, const Class* clasp, js::GlobalObject* global,
|
||||
gc::AllocKind kind, NativeObject* obj);
|
||||
|
||||
void fillGroup(EntryIndex entry, js::ObjectGroup* group, gc::AllocKind kind,
|
||||
NativeObject* obj)
|
||||
{
|
||||
MOZ_ASSERT(obj->group() == group);
|
||||
return fill(entry, group->clasp(), group, kind, obj);
|
||||
}
|
||||
|
||||
/* Invalidate any entries which might produce an object with shape/proto. */
|
||||
void invalidateEntriesForShape(JSContext* cx, HandleShape shape, HandleObject proto);
|
||||
|
||||
private:
|
||||
EntryIndex makeIndex(const Class* clasp, gc::Cell* key, gc::AllocKind kind) {
|
||||
uintptr_t hash = (uintptr_t(clasp) ^ uintptr_t(key)) + size_t(kind);
|
||||
return hash % mozilla::ArrayLength(entries);
|
||||
}
|
||||
|
||||
bool lookup(const Class* clasp, gc::Cell* key, gc::AllocKind kind, EntryIndex* pentry) {
|
||||
*pentry = makeIndex(clasp, key, kind);
|
||||
Entry* entry = &entries[*pentry];
|
||||
|
||||
/* N.B. Lookups with the same clasp/key but different kinds map to different entries. */
|
||||
return entry->clasp == clasp && entry->key == key;
|
||||
}
|
||||
|
||||
void fill(EntryIndex entry_, const Class* clasp, gc::Cell* key, gc::AllocKind kind,
|
||||
NativeObject* obj) {
|
||||
MOZ_ASSERT(unsigned(entry_) < mozilla::ArrayLength(entries));
|
||||
MOZ_ASSERT(entry_ == makeIndex(clasp, key, kind));
|
||||
Entry* entry = &entries[entry_];
|
||||
|
||||
entry->clasp = clasp;
|
||||
entry->key = key;
|
||||
entry->kind = kind;
|
||||
|
||||
entry->nbytes = gc::Arena::thingSize(kind);
|
||||
js_memcpy(&entry->templateObject, obj, entry->nbytes);
|
||||
}
|
||||
|
||||
static void copyCachedToObject(NativeObject* dst, NativeObject* src, gc::AllocKind kind) {
|
||||
js_memcpy(dst, src, gc::Arena::thingSize(kind));
|
||||
Shape::writeBarrierPost(&dst->shape_, nullptr, dst->shape_);
|
||||
ObjectGroup::writeBarrierPost(&dst->group_, nullptr, dst->group_);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* A FreeOp can do one thing: free memory. For convenience, it has delete_
|
||||
* convenience methods that also call destructors.
|
||||
@ -615,6 +353,8 @@ class PerThreadData : public PerThreadDataFriendFields
|
||||
#endif
|
||||
};
|
||||
|
||||
using ScriptAndCountsVector = GCVector<ScriptAndCounts, 0, SystemAllocPolicy>;
|
||||
|
||||
class AutoLockForExclusiveAccess;
|
||||
} // namespace js
|
||||
|
||||
@ -1292,17 +1032,9 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||
#endif
|
||||
|
||||
private:
|
||||
js::MathCache* mathCache_;
|
||||
js::MathCache* createMathCache(JSContext* cx);
|
||||
mozilla::Maybe<js::SharedImmutableStringsCache> sharedImmutableStrings_;
|
||||
public:
|
||||
js::MathCache* getMathCache(JSContext* cx) {
|
||||
return mathCache_ ? mathCache_ : createMathCache(cx);
|
||||
}
|
||||
js::MathCache* maybeGetMathCache() {
|
||||
return mathCache_;
|
||||
}
|
||||
|
||||
public:
|
||||
// If this particular JSRuntime has a SharedImmutableStringsCache, return a
|
||||
// pointer to it, otherwise return nullptr.
|
||||
js::SharedImmutableStringsCache* maybeThisRuntimeSharedImmutableStrings() {
|
||||
@ -1317,14 +1049,6 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||
return parentRuntime ? parentRuntime->sharedImmutableStrings() : *sharedImmutableStrings_;
|
||||
}
|
||||
|
||||
js::GSNCache gsnCache;
|
||||
js::ScopeCoordinateNameCache scopeCoordinateNameCache;
|
||||
js::NewObjectCache newObjectCache;
|
||||
js::NativeIterCache nativeIterCache;
|
||||
js::UncompressedSourceCache uncompressedSourceCache;
|
||||
js::EvalCache evalCache;
|
||||
js::LazyScriptCache lazyScriptCache;
|
||||
|
||||
// Pool of maps used during parse/emit. This may be modified by threads
|
||||
// with an ExclusiveContext and requires a lock. Active compilations
|
||||
// prevent the pool from being purged during GCs.
|
||||
|
@ -3538,7 +3538,7 @@ RemoveReferencedNames(JSContext* cx, HandleScript script, PropertyNameSet& remai
|
||||
|
||||
case JSOP_GETALIASEDVAR:
|
||||
case JSOP_SETALIASEDVAR:
|
||||
name = ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc);
|
||||
name = ScopeCoordinateName(cx->caches.scopeCoordinateNameCache, script, pc);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -24,8 +24,8 @@
|
||||
#include "jscompartmentinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/Caches-inl.h"
|
||||
#include "vm/NativeObject-inl.h"
|
||||
#include "vm/Runtime-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::gc;
|
||||
@ -1572,7 +1572,7 @@ EmptyShape::insertInitialShape(ExclusiveContext* cx, HandleShape shape, HandleOb
|
||||
*/
|
||||
if (cx->isJSContext()) {
|
||||
JSContext* ncx = cx->asJSContext();
|
||||
ncx->runtime()->newObjectCache.invalidateEntriesForShape(ncx, shape, proto);
|
||||
ncx->caches.newObjectCache.invalidateEntriesForShape(ncx, shape, proto);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "gc/Barrier.h"
|
||||
#include "gc/Zone.h"
|
||||
|
||||
#include "vm/Runtime-inl.h"
|
||||
#include "vm/Caches-inl.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user