mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 07:15:46 +00:00
Backout d62929fa4325 for talos crashes
This commit is contained in:
parent
1ad046b572
commit
9476c8d8ec
@ -147,7 +147,6 @@ static bool sCCLockedOut;
|
||||
static PRTime sCCLockedOutTime;
|
||||
|
||||
static js::GCSliceCallback sPrevGCSliceCallback;
|
||||
static js::AnalysisPurgeCallback sPrevAnalysisPurgeCallback;
|
||||
|
||||
// The number of currently pending document loads. This count isn't
|
||||
// guaranteed to always reflect reality and can't easily as we don't
|
||||
@ -200,17 +199,6 @@ static nsIScriptSecurityManager *sSecurityManager;
|
||||
|
||||
static bool sGCOnMemoryPressure;
|
||||
|
||||
static PRTime
|
||||
GetCollectionTimeDelta()
|
||||
{
|
||||
PRTime now = PR_Now();
|
||||
if (sFirstCollectionTime) {
|
||||
return now - sFirstCollectionTime;
|
||||
}
|
||||
sFirstCollectionTime = now;
|
||||
return 0;
|
||||
}
|
||||
|
||||
class nsMemoryPressureObserver MOZ_FINAL : public nsIObserver
|
||||
{
|
||||
public:
|
||||
@ -3129,7 +3117,12 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener,
|
||||
Telemetry::Accumulate(Telemetry::FORGET_SKIPPABLE_MAX,
|
||||
sMaxForgetSkippableTime / PR_USEC_PER_MSEC);
|
||||
|
||||
PRTime delta = GetCollectionTimeDelta();
|
||||
PRTime delta = 0;
|
||||
if (sFirstCollectionTime) {
|
||||
delta = now - sFirstCollectionTime;
|
||||
} else {
|
||||
sFirstCollectionTime = now;
|
||||
}
|
||||
|
||||
PRUint32 cleanups = sForgetSkippableBeforeCC ? sForgetSkippableBeforeCC : 1;
|
||||
PRUint32 minForgetSkippableTime = (sMinForgetSkippableTime == PR_UINT32_MAX)
|
||||
@ -3515,7 +3508,13 @@ DOMGCSliceCallback(JSRuntime *aRt, js::GCProgress aProgress, const js::GCDescrip
|
||||
NS_ASSERTION(NS_IsMainThread(), "GCs must run on the main thread");
|
||||
|
||||
if (aProgress == js::GC_CYCLE_END) {
|
||||
PRTime delta = GetCollectionTimeDelta();
|
||||
PRTime now = PR_Now();
|
||||
PRTime delta = 0;
|
||||
if (sFirstCollectionTime) {
|
||||
delta = now - sFirstCollectionTime;
|
||||
} else {
|
||||
sFirstCollectionTime = now;
|
||||
}
|
||||
|
||||
if (sPostGCEventsToConsole) {
|
||||
NS_NAMED_LITERAL_STRING(kFmt, "GC(T+%.1f) ");
|
||||
@ -3532,7 +3531,7 @@ DOMGCSliceCallback(JSRuntime *aRt, js::GCProgress aProgress, const js::GCDescrip
|
||||
|
||||
if (sPostGCEventsToConsole || sPostGCEventsToObserver) {
|
||||
nsString json;
|
||||
json.Adopt(aDesc.formatJSON(aRt, PR_Now()));
|
||||
json.Adopt(aDesc.formatJSON(aRt, now));
|
||||
nsRefPtr<NotifyGCEndRunnable> notify = new NotifyGCEndRunnable(json);
|
||||
NS_DispatchToMainThread(notify);
|
||||
}
|
||||
@ -3589,32 +3588,6 @@ DOMGCSliceCallback(JSRuntime *aRt, js::GCProgress aProgress, const js::GCDescrip
|
||||
(*sPrevGCSliceCallback)(aRt, aProgress, aDesc);
|
||||
}
|
||||
|
||||
static void
|
||||
DOMAnalysisPurgeCallback(JSRuntime *aRt, JSFlatString *aDesc)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "GCs must run on the main thread");
|
||||
|
||||
PRTime delta = GetCollectionTimeDelta();
|
||||
|
||||
if (sPostGCEventsToConsole) {
|
||||
NS_NAMED_LITERAL_STRING(kFmt, "Analysis Purge (T+%.1f) ");
|
||||
nsString prefix;
|
||||
prefix.Adopt(nsTextFormatter::smprintf(kFmt.get(),
|
||||
double(delta) / PR_USEC_PER_SEC));
|
||||
|
||||
nsDependentJSString stats(aDesc);
|
||||
nsString msg = prefix + stats;
|
||||
|
||||
nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
||||
if (cs) {
|
||||
cs->LogStringMessage(msg.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (sPrevAnalysisPurgeCallback)
|
||||
(*sPrevAnalysisPurgeCallback)(aRt, aDesc);
|
||||
}
|
||||
|
||||
// Script object mananagement - note duplicate implementation
|
||||
// in nsJSRuntime below...
|
||||
nsresult
|
||||
@ -4031,7 +4004,6 @@ nsJSRuntime::Init()
|
||||
NS_ASSERTION(NS_IsMainThread(), "bad");
|
||||
|
||||
sPrevGCSliceCallback = js::SetGCSliceCallback(sRuntime, DOMGCSliceCallback);
|
||||
sPrevAnalysisPurgeCallback = js::SetAnalysisPurgeCallback(sRuntime, DOMAnalysisPurgeCallback);
|
||||
|
||||
// Set up the structured clone callbacks.
|
||||
static JSStructuredCloneCallbacks cloneCallbacks = {
|
||||
@ -4126,12 +4098,6 @@ nsJSRuntime::Init()
|
||||
SetMemoryGCPrefChangedCallback("javascript.options.mem.gc_high_frequency_high_limit_mb",
|
||||
(void *)JSGC_HIGH_FREQUENCY_HIGH_LIMIT);
|
||||
|
||||
Preferences::RegisterCallback(SetMemoryGCPrefChangedCallback,
|
||||
"javascript.options.mem.analysis_purge_mb",
|
||||
(void *)JSGC_ANALYSIS_PURGE_TRIGGER);
|
||||
SetMemoryGCPrefChangedCallback("javascript.options.mem.analysis_purge_mb",
|
||||
(void *)JSGC_ANALYSIS_PURGE_TRIGGER);
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (!obs)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -963,8 +963,8 @@ ParallelArrayObject::create(JSContext *cx, HandleObject buffer, uint32_t offset,
|
||||
TypeObject *bufferType = buffer->getType(cx);
|
||||
TypeObject *resultType = result->getType(cx);
|
||||
if (!bufferType->unknownProperties() && !resultType->unknownProperties()) {
|
||||
HeapTypeSet *bufferIndexTypes = bufferType->getProperty(cx, JSID_VOID, false);
|
||||
HeapTypeSet *resultIndexTypes = resultType->getProperty(cx, JSID_VOID, true);
|
||||
TypeSet *bufferIndexTypes = bufferType->getProperty(cx, JSID_VOID, false);
|
||||
TypeSet *resultIndexTypes = resultType->getProperty(cx, JSID_VOID, true);
|
||||
bufferIndexTypes->addSubset(cx, resultIndexTypes);
|
||||
}
|
||||
}
|
||||
|
@ -806,7 +806,6 @@ static JSFunctionSpecWithHelp TestingFunctions[] = {
|
||||
" 10: Incremental GC in multiple slices\n"
|
||||
" 11: Verify post write barriers between instructions\n"
|
||||
" 12: Verify post write barriers between paints\n"
|
||||
" 13: Purge analysis state when memory is allocated\n"
|
||||
" Period specifies that collection happens every n allocations.\n"),
|
||||
|
||||
JS_FN_HELP("schedulegc", ScheduleGC, 1, 0,
|
||||
|
@ -263,21 +263,12 @@ class LifoAlloc
|
||||
latest->release(mark);
|
||||
}
|
||||
|
||||
void releaseAll() {
|
||||
JS_ASSERT(!markCount);
|
||||
latest = first;
|
||||
if (latest)
|
||||
latest->resetBump();
|
||||
}
|
||||
|
||||
/* Get the total "used" (occupied bytes) count for the arena chunks. */
|
||||
size_t used() const {
|
||||
size_t accum = 0;
|
||||
BumpChunk *it = first;
|
||||
while (it) {
|
||||
accum += it->used();
|
||||
if (it == latest)
|
||||
break;
|
||||
it = it->next();
|
||||
}
|
||||
return accum;
|
||||
|
@ -2642,11 +2642,7 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod
|
||||
|
||||
if (!EmitTree(cx, bce, body))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Always end the script with a JSOP_STOP. Some other parts of the codebase
|
||||
* depend on this opcode, e.g. js_InternalInterpret.
|
||||
*/
|
||||
|
||||
if (Emit1(cx, bce, JSOP_STOP) < 0)
|
||||
return false;
|
||||
|
||||
|
@ -47,7 +47,7 @@ ScriptAnalysis::addJump(JSContext *cx, unsigned offset,
|
||||
|
||||
Bytecode *&code = codeArray[offset];
|
||||
if (!code) {
|
||||
code = cx->analysisLifoAlloc().new_<Bytecode>();
|
||||
code = cx->typeLifoAlloc().new_<Bytecode>();
|
||||
if (!code) {
|
||||
setOOM(cx);
|
||||
return false;
|
||||
@ -96,13 +96,13 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(cx->compartment->activeAnalysis);
|
||||
JS_ASSERT(!ranBytecode());
|
||||
LifoAlloc &alloc = cx->analysisLifoAlloc();
|
||||
LifoAlloc &tla = cx->typeLifoAlloc();
|
||||
|
||||
numSlots = TotalSlots(script);
|
||||
|
||||
unsigned length = script->length;
|
||||
codeArray = alloc.newArray<Bytecode*>(length);
|
||||
escapedSlots = alloc.newArray<bool>(numSlots);
|
||||
codeArray = tla.newArray<Bytecode*>(length);
|
||||
escapedSlots = tla.newArray<bool>(numSlots);
|
||||
|
||||
if (!codeArray || !escapedSlots) {
|
||||
setOOM(cx);
|
||||
@ -173,7 +173,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
||||
unsigned forwardCatch = 0;
|
||||
|
||||
/* Fill in stack depth and definitions at initial bytecode. */
|
||||
Bytecode *startcode = alloc.new_<Bytecode>();
|
||||
Bytecode *startcode = tla.new_<Bytecode>();
|
||||
if (!startcode) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
@ -270,10 +270,10 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
||||
*/
|
||||
if ((js_CodeSpec[op].format & JOF_TYPESET) && cx->typeInferenceEnabled()) {
|
||||
if (nTypeSets < script->nTypeSets) {
|
||||
code->observedTypes = typeArray[nTypeSets++].toStackTypeSet();
|
||||
code->observedTypes = &typeArray[nTypeSets++];
|
||||
} else {
|
||||
JS_ASSERT(nTypeSets == UINT16_MAX);
|
||||
code->observedTypes = typeArray[nTypeSets - 1].toStackTypeSet();
|
||||
code->observedTypes = &typeArray[nTypeSets - 1];
|
||||
}
|
||||
}
|
||||
|
||||
@ -460,14 +460,6 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
||||
isInlineable = false;
|
||||
break;
|
||||
|
||||
case JSOP_GETPROP:
|
||||
case JSOP_CALLPROP:
|
||||
case JSOP_LENGTH:
|
||||
case JSOP_GETELEM:
|
||||
case JSOP_CALLELEM:
|
||||
numPropertyReads_++;
|
||||
break;
|
||||
|
||||
/* Additional opcodes which can be compiled but which can't be inlined. */
|
||||
case JSOP_ARGUMENTS:
|
||||
case JSOP_THROW:
|
||||
@ -517,6 +509,11 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
||||
case JSOP_TYPEOF:
|
||||
case JSOP_TYPEOFEXPR:
|
||||
case JSOP_VOID:
|
||||
case JSOP_GETPROP:
|
||||
case JSOP_CALLPROP:
|
||||
case JSOP_LENGTH:
|
||||
case JSOP_GETELEM:
|
||||
case JSOP_CALLELEM:
|
||||
case JSOP_TOID:
|
||||
case JSOP_SETELEM:
|
||||
case JSOP_IMPLICITTHIS:
|
||||
@ -605,7 +602,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
||||
Bytecode *&nextcode = codeArray[successorOffset];
|
||||
|
||||
if (!nextcode) {
|
||||
nextcode = alloc.new_<Bytecode>();
|
||||
nextcode = tla.new_<Bytecode>();
|
||||
if (!nextcode) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
@ -637,25 +634,6 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
||||
*/
|
||||
if (!script->analyzedArgsUsage())
|
||||
analyzeSSA(cx);
|
||||
|
||||
/*
|
||||
* If the script has JIT information (we are reanalyzing the script after
|
||||
* a purge), add safepoints for the targets of any cross chunk edges in
|
||||
* the script. These safepoints are normally added when the JITScript is
|
||||
* constructed, but will have been lost during the purge.
|
||||
*/
|
||||
#ifdef JS_METHODJIT
|
||||
mjit::JITScript *jit = NULL;
|
||||
for (int constructing = 0; constructing <= 1 && !jit; constructing++) {
|
||||
for (int barriers = 0; barriers <= 1 && !jit; barriers++)
|
||||
jit = script->getJIT((bool) constructing, (bool) barriers);
|
||||
}
|
||||
if (jit) {
|
||||
mjit::CrossChunkEdge *edges = jit->edges();
|
||||
for (size_t i = 0; i < jit->nedges; i++)
|
||||
getCode(edges[i].target).safePoint = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
@ -673,9 +651,9 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
|
||||
return;
|
||||
}
|
||||
|
||||
LifoAlloc &alloc = cx->analysisLifoAlloc();
|
||||
LifoAlloc &tla = cx->typeLifoAlloc();
|
||||
|
||||
lifetimes = alloc.newArray<LifetimeVariable>(numSlots);
|
||||
lifetimes = tla.newArray<LifetimeVariable>(numSlots);
|
||||
if (!lifetimes) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
@ -797,7 +775,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
|
||||
/* Restore all saved variables. :FIXME: maybe do this precisely. */
|
||||
for (unsigned i = 0; i < savedCount; i++) {
|
||||
LifetimeVariable &var = *saved[i];
|
||||
var.lifetime = alloc.new_<Lifetime>(offset, var.savedEnd, var.saved);
|
||||
var.lifetime = tla.new_<Lifetime>(offset, var.savedEnd, var.saved);
|
||||
if (!var.lifetime) {
|
||||
cx->free_(saved);
|
||||
setOOM(cx);
|
||||
@ -864,7 +842,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
|
||||
if (loop && loop->entry > loop->lastBlock)
|
||||
loop->lastBlock = loop->entry;
|
||||
|
||||
LoopAnalysis *nloop = alloc.new_<LoopAnalysis>();
|
||||
LoopAnalysis *nloop = tla.new_<LoopAnalysis>();
|
||||
if (!nloop) {
|
||||
cx->free_(saved);
|
||||
setOOM(cx);
|
||||
@ -914,7 +892,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
|
||||
* Jumping to a place where this variable is live. Make a new
|
||||
* lifetime segment for the variable.
|
||||
*/
|
||||
var.lifetime = alloc.new_<Lifetime>(offset, var.savedEnd, var.saved);
|
||||
var.lifetime = tla.new_<Lifetime>(offset, var.savedEnd, var.saved);
|
||||
if (!var.lifetime) {
|
||||
cx->free_(saved);
|
||||
setOOM(cx);
|
||||
@ -978,7 +956,7 @@ ScriptAnalysis::addVariable(JSContext *cx, LifetimeVariable &var, unsigned offse
|
||||
}
|
||||
}
|
||||
}
|
||||
var.lifetime = cx->analysisLifoAlloc().new_<Lifetime>(offset, var.savedEnd, var.saved);
|
||||
var.lifetime = cx->typeLifoAlloc().new_<Lifetime>(offset, var.savedEnd, var.saved);
|
||||
if (!var.lifetime) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
@ -993,7 +971,7 @@ ScriptAnalysis::killVariable(JSContext *cx, LifetimeVariable &var, unsigned offs
|
||||
{
|
||||
if (!var.lifetime) {
|
||||
/* Make a point lifetime indicating the write. */
|
||||
Lifetime *lifetime = cx->analysisLifoAlloc().new_<Lifetime>(offset, var.savedEnd, var.saved);
|
||||
Lifetime *lifetime = cx->typeLifoAlloc().new_<Lifetime>(offset, var.savedEnd, var.saved);
|
||||
if (!lifetime) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
@ -1024,7 +1002,7 @@ ScriptAnalysis::killVariable(JSContext *cx, LifetimeVariable &var, unsigned offs
|
||||
* We set the new interval's savedEnd to 0, since it will always be
|
||||
* adjacent to the old interval, so it never needs to be extended.
|
||||
*/
|
||||
var.lifetime = cx->analysisLifoAlloc().new_<Lifetime>(start, 0, var.lifetime);
|
||||
var.lifetime = cx->typeLifoAlloc().new_<Lifetime>(start, 0, var.lifetime);
|
||||
if (!var.lifetime) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
@ -1113,7 +1091,7 @@ ScriptAnalysis::extendVariable(JSContext *cx, LifetimeVariable &var,
|
||||
}
|
||||
JS_ASSERT(savedEnd <= end);
|
||||
if (savedEnd > segment->end) {
|
||||
Lifetime *tail = cx->analysisLifoAlloc().new_<Lifetime>(savedEnd, 0, segment->next);
|
||||
Lifetime *tail = cx->typeLifoAlloc().new_<Lifetime>(savedEnd, 0, segment->next);
|
||||
if (!tail) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
@ -1190,7 +1168,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
return;
|
||||
}
|
||||
|
||||
LifoAlloc &alloc = cx->analysisLifoAlloc();
|
||||
LifoAlloc &tla = cx->typeLifoAlloc();
|
||||
unsigned maxDepth = script->nslots - script->nfixed;
|
||||
|
||||
/*
|
||||
@ -1374,7 +1352,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
unsigned xuses = ExtendedUse(pc) ? nuses + 1 : nuses;
|
||||
|
||||
if (xuses) {
|
||||
code->poppedValues = alloc.newArray<SSAValue>(xuses);
|
||||
code->poppedValues = tla.newArray<SSAValue>(xuses);
|
||||
if (!code->poppedValues) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
@ -1397,7 +1375,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
}
|
||||
|
||||
if (xuses) {
|
||||
SSAUseChain *useChains = alloc.newArray<SSAUseChain>(xuses);
|
||||
SSAUseChain *useChains = tla.newArray<SSAUseChain>(xuses);
|
||||
if (!useChains) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
@ -1424,7 +1402,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
|
||||
unsigned xdefs = ExtendedDef(pc) ? ndefs + 1 : ndefs;
|
||||
if (xdefs) {
|
||||
code->pushedUses = alloc.newArray<SSAUseChain *>(xdefs);
|
||||
code->pushedUses = tla.newArray<SSAUseChain *>(xdefs);
|
||||
if (!code->pushedUses) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
@ -1605,8 +1583,8 @@ PhiNodeCapacity(unsigned length)
|
||||
bool
|
||||
ScriptAnalysis::makePhi(JSContext *cx, uint32_t slot, uint32_t offset, SSAValue *pv)
|
||||
{
|
||||
SSAPhiNode *node = cx->analysisLifoAlloc().new_<SSAPhiNode>();
|
||||
SSAValue *options = cx->analysisLifoAlloc().newArray<SSAValue>(PhiNodeCapacity(0));
|
||||
SSAPhiNode *node = cx->typeLifoAlloc().new_<SSAPhiNode>();
|
||||
SSAValue *options = cx->typeLifoAlloc().newArray<SSAValue>(PhiNodeCapacity(0));
|
||||
if (!node || !options) {
|
||||
setOOM(cx);
|
||||
return false;
|
||||
@ -1638,7 +1616,7 @@ ScriptAnalysis::insertPhi(JSContext *cx, SSAValue &phi, const SSAValue &v)
|
||||
if (trackUseChain(v)) {
|
||||
SSAUseChain *&uses = useChain(v);
|
||||
|
||||
SSAUseChain *use = cx->analysisLifoAlloc().new_<SSAUseChain>();
|
||||
SSAUseChain *use = cx->typeLifoAlloc().new_<SSAUseChain>();
|
||||
if (!use) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
@ -1657,7 +1635,7 @@ ScriptAnalysis::insertPhi(JSContext *cx, SSAValue &phi, const SSAValue &v)
|
||||
}
|
||||
|
||||
SSAValue *newOptions =
|
||||
cx->analysisLifoAlloc().newArray<SSAValue>(PhiNodeCapacity(node->length + 1));
|
||||
cx->typeLifoAlloc().newArray<SSAValue>(PhiNodeCapacity(node->length + 1));
|
||||
if (!newOptions) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
@ -1857,7 +1835,7 @@ ScriptAnalysis::freezeNewValues(JSContext *cx, uint32_t offset)
|
||||
return;
|
||||
}
|
||||
|
||||
code.newValues = cx->analysisLifoAlloc().newArray<SlotValue>(count + 1);
|
||||
code.newValues = cx->typeLifoAlloc().newArray<SlotValue>(count + 1);
|
||||
if (!code.newValues) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
@ -2036,7 +2014,7 @@ CrossScriptSSA::foldValue(const CrossSSAValue &cv)
|
||||
*/
|
||||
ScriptAnalysis *analysis = frame.script->analysis();
|
||||
SSAValue toidv = analysis->poppedValue(pc, 0);
|
||||
if (analysis->getValueTypes(toidv)->getKnownTypeTag() == JSVAL_TYPE_INT32)
|
||||
if (analysis->getValueTypes(toidv)->getKnownTypeTag(cx) == JSVAL_TYPE_INT32)
|
||||
return foldValue(CrossSSAValue(cv.frame, toidv));
|
||||
break;
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ class Bytecode
|
||||
|
||||
union {
|
||||
/* If this is a JOF_TYPESET opcode, index into the observed types for the op. */
|
||||
types::StackTypeSet *observedTypes;
|
||||
types::TypeSet *observedTypes;
|
||||
|
||||
/* If this is a loop head (TRACE or NOTRACE), information about the loop. */
|
||||
LoopAnalysis *loop;
|
||||
@ -164,7 +164,7 @@ class Bytecode
|
||||
/* --------- Type inference --------- */
|
||||
|
||||
/* Types for all values pushed by this bytecode. */
|
||||
types::StackTypeSet *pushedTypes;
|
||||
types::TypeSet *pushedTypes;
|
||||
|
||||
/* Any type barriers in place at this bytecode. */
|
||||
types::TypeBarrier *typeBarriers;
|
||||
@ -739,7 +739,7 @@ class SSAValue
|
||||
*/
|
||||
struct SSAPhiNode
|
||||
{
|
||||
types::StackTypeSet types;
|
||||
types::TypeSet types;
|
||||
uint32_t slot;
|
||||
uint32_t length;
|
||||
SSAValue *options;
|
||||
@ -809,7 +809,6 @@ class ScriptAnalysis
|
||||
Bytecode **codeArray;
|
||||
|
||||
uint32_t numSlots;
|
||||
uint32_t numPropertyReads_;
|
||||
|
||||
bool outOfMemory;
|
||||
bool hadFailure;
|
||||
@ -873,9 +872,6 @@ class ScriptAnalysis
|
||||
bool inlineable(uint32_t argc) { return isInlineable && argc == script->function()->nargs; }
|
||||
bool jaegerCompileable() { return isJaegerCompileable; }
|
||||
|
||||
/* Number of property read opcodes in the script. */
|
||||
uint32_t numPropertyReads() const { return numPropertyReads_; }
|
||||
|
||||
/* Whether there are POPV/SETRVAL bytecodes which can write to the frame's rval. */
|
||||
bool usesReturnValue() const { return usesReturnValue_; }
|
||||
|
||||
@ -929,7 +925,7 @@ class ScriptAnalysis
|
||||
return (cs->format & JOF_POST) && !popGuaranteed(pc);
|
||||
}
|
||||
|
||||
types::StackTypeSet *bytecodeTypes(const jsbytecode *pc) {
|
||||
types::TypeSet *bytecodeTypes(const jsbytecode *pc) {
|
||||
JS_ASSERT(js_CodeSpec[*pc].format & JOF_TYPESET);
|
||||
return getCode(pc).observedTypes;
|
||||
}
|
||||
@ -950,15 +946,15 @@ class ScriptAnalysis
|
||||
}
|
||||
const SlotValue *newValues(const jsbytecode *pc) { return newValues(pc - script->code); }
|
||||
|
||||
types::StackTypeSet *pushedTypes(uint32_t offset, uint32_t which = 0) {
|
||||
types::TypeSet *pushedTypes(uint32_t offset, uint32_t which = 0) {
|
||||
JS_ASSERT(offset < script->length);
|
||||
JS_ASSERT(which < GetDefCount(script, offset) +
|
||||
(ExtendedDef(script->code + offset) ? 1 : 0));
|
||||
types::StackTypeSet *array = getCode(offset).pushedTypes;
|
||||
types::TypeSet *array = getCode(offset).pushedTypes;
|
||||
JS_ASSERT(array);
|
||||
return array + which;
|
||||
}
|
||||
types::StackTypeSet *pushedTypes(const jsbytecode *pc, uint32_t which) {
|
||||
types::TypeSet *pushedTypes(const jsbytecode *pc, uint32_t which) {
|
||||
return pushedTypes(pc - script->code, which);
|
||||
}
|
||||
|
||||
@ -992,7 +988,7 @@ class ScriptAnalysis
|
||||
|
||||
inline void addPushedType(JSContext *cx, uint32_t offset, uint32_t which, types::Type type);
|
||||
|
||||
types::StackTypeSet *getValueTypes(const SSAValue &v) {
|
||||
types::TypeSet *getValueTypes(const SSAValue &v) {
|
||||
switch (v.kind()) {
|
||||
case SSAValue::PUSHED:
|
||||
return pushedTypes(v.pushedOffset(), v.pushedIndex());
|
||||
@ -1018,10 +1014,10 @@ class ScriptAnalysis
|
||||
}
|
||||
}
|
||||
|
||||
types::StackTypeSet *poppedTypes(uint32_t offset, uint32_t which) {
|
||||
types::TypeSet *poppedTypes(uint32_t offset, uint32_t which) {
|
||||
return getValueTypes(poppedValue(offset, which));
|
||||
}
|
||||
types::StackTypeSet *poppedTypes(const jsbytecode *pc, uint32_t which) {
|
||||
types::TypeSet *poppedTypes(const jsbytecode *pc, uint32_t which) {
|
||||
return getValueTypes(poppedValue(pc, which));
|
||||
}
|
||||
|
||||
@ -1161,12 +1157,9 @@ class ScriptAnalysis
|
||||
Vector<SSAPhiNode *> phiNodes;
|
||||
bool hasGetSet;
|
||||
bool hasHole;
|
||||
types::StackTypeSet *forTypes;
|
||||
bool hasPropertyReadTypes;
|
||||
uint32_t propertyReadIndex;
|
||||
types::TypeSet *forTypes;
|
||||
TypeInferenceState(JSContext *cx)
|
||||
: phiNodes(cx), hasGetSet(false), hasHole(false), forTypes(NULL),
|
||||
hasPropertyReadTypes(false), propertyReadIndex(0)
|
||||
: phiNodes(cx), hasGetSet(false), hasHole(false), forTypes(NULL)
|
||||
{}
|
||||
};
|
||||
|
||||
@ -1276,7 +1269,7 @@ class CrossScriptSSA
|
||||
return res;
|
||||
}
|
||||
|
||||
types::StackTypeSet *getValueTypes(const CrossSSAValue &cv) {
|
||||
types::TypeSet *getValueTypes(const CrossSSAValue &cv) {
|
||||
return getFrame(cv.frame).script->analysis()->getValueTypes(cv.v);
|
||||
}
|
||||
|
||||
|
@ -807,8 +807,6 @@ JSRuntime::JSRuntime()
|
||||
gcCallback(NULL),
|
||||
gcSliceCallback(NULL),
|
||||
gcFinalizeCallback(NULL),
|
||||
analysisPurgeCallback(NULL),
|
||||
analysisPurgeTriggerBytes(0),
|
||||
gcMallocBytes(0),
|
||||
gcBlackRootsTraceOp(NULL),
|
||||
gcBlackRootsData(NULL),
|
||||
@ -3064,9 +3062,6 @@ JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32_t value)
|
||||
case JSGC_DYNAMIC_MARK_SLICE:
|
||||
rt->gcDynamicMarkSlice = value;
|
||||
break;
|
||||
case JSGC_ANALYSIS_PURGE_TRIGGER:
|
||||
rt->analysisPurgeTriggerBytes = value * 1024 * 1024;
|
||||
break;
|
||||
default:
|
||||
JS_ASSERT(key == JSGC_MODE);
|
||||
rt->gcMode = JSGCMode(value);
|
||||
@ -3113,8 +3108,6 @@ JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key)
|
||||
return rt->gcDynamicHeapGrowth;
|
||||
case JSGC_DYNAMIC_MARK_SLICE:
|
||||
return rt->gcDynamicMarkSlice;
|
||||
case JSGC_ANALYSIS_PURGE_TRIGGER:
|
||||
return rt->analysisPurgeTriggerBytes / 1024 / 1024;
|
||||
default:
|
||||
JS_ASSERT(key == JSGC_NUMBER);
|
||||
return uint32_t(rt->gcNumber);
|
||||
@ -7108,8 +7101,7 @@ JS_SetGCZeal(JSContext *cx, uint8_t zeal, uint32_t frequency)
|
||||
" 9: Incremental GC in two slices: 1) mark all 2) new marking and finish\n"
|
||||
" 10: Incremental GC in multiple slices\n"
|
||||
" 11: Verify post write barriers between instructions\n"
|
||||
" 12: Verify post write barriers between paints\n"
|
||||
" 13: Purge analysis state every F allocations (default: 100)\n");
|
||||
" 12: Verify post write barriers between paints\n");
|
||||
}
|
||||
const char *p = strchr(env, ',');
|
||||
zeal = atoi(env);
|
||||
|
@ -4096,10 +4096,7 @@ typedef enum JSGCParamKey {
|
||||
JSGC_DYNAMIC_HEAP_GROWTH = 17,
|
||||
|
||||
/* If true, high-frequency GCs will use a longer mark slice. */
|
||||
JSGC_DYNAMIC_MARK_SLICE = 18,
|
||||
|
||||
/* Number of megabytes of analysis data to allocate before purging. */
|
||||
JSGC_ANALYSIS_PURGE_TRIGGER = 19
|
||||
JSGC_DYNAMIC_MARK_SLICE = 18
|
||||
} JSGCParamKey;
|
||||
|
||||
typedef enum JSGCMode {
|
||||
|
@ -687,7 +687,6 @@ struct JSRuntime : js::RuntimeFriendFields
|
||||
bool needZealousGC() {
|
||||
if (gcNextScheduled > 0 && --gcNextScheduled == 0) {
|
||||
if (gcZeal() == js::gc::ZealAllocValue ||
|
||||
gcZeal() == js::gc::ZealPurgeAnalysisValue ||
|
||||
(gcZeal() >= js::gc::ZealIncrementalRootsThenFinish &&
|
||||
gcZeal() <= js::gc::ZealIncrementalMultipleSlices))
|
||||
{
|
||||
@ -708,9 +707,6 @@ struct JSRuntime : js::RuntimeFriendFields
|
||||
js::GCSliceCallback gcSliceCallback;
|
||||
JSFinalizeCallback gcFinalizeCallback;
|
||||
|
||||
js::AnalysisPurgeCallback analysisPurgeCallback;
|
||||
uint64_t analysisPurgeTriggerBytes;
|
||||
|
||||
private:
|
||||
/*
|
||||
* Malloc counter to measure memory pressure for GC scheduling. It runs
|
||||
@ -1296,7 +1292,6 @@ struct JSContext : js::ContextFriendFields
|
||||
bool hasAtLineOption() const { return hasRunOption(JSOPTION_ATLINE); }
|
||||
|
||||
js::LifoAlloc &tempLifoAlloc() { return runtime->tempLifoAlloc; }
|
||||
inline js::LifoAlloc &analysisLifoAlloc();
|
||||
inline js::LifoAlloc &typeLifoAlloc();
|
||||
|
||||
inline js::PropertyTree &propertyTree();
|
||||
|
@ -549,11 +549,6 @@ JSContext::setCompileOptions(unsigned newcopts)
|
||||
maybeOverrideVersion(newVersion);
|
||||
}
|
||||
|
||||
inline js::LifoAlloc &
|
||||
JSContext::analysisLifoAlloc()
|
||||
{
|
||||
return compartment->analysisLifoAlloc;
|
||||
}
|
||||
|
||||
inline js::LifoAlloc &
|
||||
JSContext::typeLifoAlloc()
|
||||
|
@ -55,8 +55,7 @@ JSCompartment::JSCompartment(JSRuntime *rt)
|
||||
hold(false),
|
||||
isSystemCompartment(false),
|
||||
lastCodeRelease(0),
|
||||
analysisLifoAlloc(LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
|
||||
typeLifoAlloc(LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
|
||||
typeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
|
||||
data(NULL),
|
||||
active(false),
|
||||
lastAnimationTime(0),
|
||||
@ -580,13 +579,11 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
|
||||
for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
script->clearAnalysis();
|
||||
script->clearPropertyReadTypes();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_FREE_TI_ARENA);
|
||||
rt->freeLifoAlloc.transferFrom(&analysisLifoAlloc);
|
||||
rt->freeLifoAlloc.transferFrom(&oldAlloc);
|
||||
}
|
||||
}
|
||||
|
@ -248,11 +248,13 @@ struct JSCompartment
|
||||
|
||||
int64_t lastCodeRelease;
|
||||
|
||||
/* Pools for analysis and type information in this compartment. */
|
||||
static const size_t LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 128 * 1024;
|
||||
js::LifoAlloc analysisLifoAlloc;
|
||||
/*
|
||||
* Pool for analysis and intermediate type information in this compartment.
|
||||
* Cleared on every GC, unless the GC happens during analysis (indicated
|
||||
* by activeAnalysis, which is implied by activeInference).
|
||||
*/
|
||||
static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 128 * 1024;
|
||||
js::LifoAlloc typeLifoAlloc;
|
||||
|
||||
bool activeAnalysis;
|
||||
bool activeInference;
|
||||
|
||||
|
@ -798,14 +798,6 @@ GCDescription::formatJSON(JSRuntime *rt, uint64_t timestamp) const
|
||||
return rt->gcStats.formatJSON(timestamp);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(AnalysisPurgeCallback)
|
||||
SetAnalysisPurgeCallback(JSRuntime *rt, AnalysisPurgeCallback callback)
|
||||
{
|
||||
AnalysisPurgeCallback old = rt->analysisPurgeCallback;
|
||||
rt->analysisPurgeCallback = callback;
|
||||
return old;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
NotifyDidPaint(JSRuntime *rt)
|
||||
{
|
||||
|
@ -799,12 +799,6 @@ typedef void
|
||||
extern JS_FRIEND_API(GCSliceCallback)
|
||||
SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback);
|
||||
|
||||
typedef void
|
||||
(* AnalysisPurgeCallback)(JSRuntime *rt, JSFlatString *desc);
|
||||
|
||||
extern JS_FRIEND_API(AnalysisPurgeCallback)
|
||||
SetAnalysisPurgeCallback(JSRuntime *rt, AnalysisPurgeCallback callback);
|
||||
|
||||
/* Was the most recent GC run incrementally? */
|
||||
extern JS_FRIEND_API(bool)
|
||||
WasIncrementalGC(JSRuntime *rt);
|
||||
@ -812,6 +806,7 @@ WasIncrementalGC(JSRuntime *rt);
|
||||
typedef JSBool
|
||||
(* DOMInstanceClassMatchesProto)(JSHandleObject protoObject, uint32_t protoID,
|
||||
uint32_t depth);
|
||||
|
||||
struct JSDOMCallbacks {
|
||||
DOMInstanceClassMatchesProto instanceClassMatchesProto;
|
||||
};
|
||||
|
@ -4793,9 +4793,6 @@ RunDebugGC(JSContext *cx)
|
||||
{
|
||||
rt->gcIncrementalLimit = rt->gcZealFrequency / 2;
|
||||
}
|
||||
} else if (type == ZealPurgeAnalysisValue) {
|
||||
if (!cx->compartment->activeAnalysis)
|
||||
cx->compartment->types.maybePurgeAnalysis(cx, /* force = */ true);
|
||||
} else {
|
||||
Collect(rt, false, SliceBudget::Unlimited, GC_NORMAL, gcreason::DEBUG_GC);
|
||||
}
|
||||
|
@ -1165,7 +1165,6 @@ const int ZealIncrementalMarkAllThenFinish = 9;
|
||||
const int ZealIncrementalMultipleSlices = 10;
|
||||
const int ZealVerifierPostValue = 11;
|
||||
const int ZealFrameVerifierPostValue = 12;
|
||||
const int ZealPurgeAnalysisValue = 13;
|
||||
|
||||
enum VerifierType {
|
||||
PreBarrierVerifier,
|
||||
|
1170
js/src/jsinfer.cpp
1170
js/src/jsinfer.cpp
File diff suppressed because it is too large
Load Diff
273
js/src/jsinfer.h
273
js/src/jsinfer.h
@ -135,35 +135,17 @@ inline Type GetValueType(JSContext *cx, const Value &val);
|
||||
* Inference constructs a global web of constraints relating the contents of
|
||||
* type sets particular to various scripts and type objects within a
|
||||
* compartment. This data can consume a significant amount of memory, and to
|
||||
* avoid this building up we try to clear it with some regularity.
|
||||
* avoid this building up we try to clear it with some regularity. On each GC
|
||||
* which occurs while we are not actively working with inference or other
|
||||
* analysis information, we clear out all generated constraints, all type sets
|
||||
* describing stack types within scripts, and (normally) all data describing
|
||||
* type objects for particular JS objects (see the lazy type objects overview
|
||||
* below). JIT code depends on this data and is cleared as well.
|
||||
*
|
||||
* There are two operations which can clear inference and analysis data.
|
||||
*
|
||||
* - Analysis purges clear analysis information while retaining jitcode.
|
||||
*
|
||||
* - GCs may clear both analysis information and jitcode. Sometimes GCs will
|
||||
* preserve all information and code, and will not collect any scripts,
|
||||
* type objects or singleton JS objects.
|
||||
*
|
||||
* There are several categories of data affected differently by the above
|
||||
* operations.
|
||||
*
|
||||
* - Data cleared by every analysis purge and non-preserving GC. This includes
|
||||
* the ScriptAnalysis for each analyzed script and data from each analysis
|
||||
* pass performed, type sets for stack values, and all type constraints for
|
||||
* such type sets and for observed/argument/local type sets on scripts
|
||||
* (TypeSet::constraintsPurged, aka StackTypeSet). This is exactly the data
|
||||
* allocated using compartment->analysisLifoAlloc.
|
||||
*
|
||||
* - Data cleared by non-preserving GCs. This includes property type sets for
|
||||
* singleton JS objects, property read input type sets, type constraints on
|
||||
* all type sets, and dead references in all type sets. This data is all
|
||||
* allocated using compartment->typeLifoAlloc; the GC copies live data into a
|
||||
* new allocator and clears the old one.
|
||||
*
|
||||
* - Data cleared occasionally by non-preserving GCs. TypeScripts and the data
|
||||
* in their sets are occasionally destroyed during GC. When a JSScript or
|
||||
* TypeObject is swept, type information for its contents is destroyed.
|
||||
* All this data is allocated into compartment->pool. Some type inference data
|
||||
* lives across GCs: type sets for scripts and non-singleton type objects, and
|
||||
* propeties for such type objects. This data is also allocated into
|
||||
* compartment->pool, but everything still live is copied to a new arena on GC.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -173,15 +155,23 @@ inline Type GetValueType(JSContext *cx, const Value &val);
|
||||
class TypeConstraint
|
||||
{
|
||||
public:
|
||||
#ifdef DEBUG
|
||||
const char *kind_;
|
||||
const char *kind() const { return kind_; }
|
||||
#else
|
||||
const char *kind() const { return NULL; }
|
||||
#endif
|
||||
|
||||
/* Next constraint listening to the same type set. */
|
||||
TypeConstraint *next;
|
||||
|
||||
TypeConstraint()
|
||||
TypeConstraint(const char *kind)
|
||||
: next(NULL)
|
||||
{}
|
||||
|
||||
/* Debugging name for this kind of constraint. */
|
||||
virtual const char *kind() = 0;
|
||||
{
|
||||
#ifdef DEBUG
|
||||
this->kind_ = kind;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Register a new type for the set this constraint is listening to. */
|
||||
virtual void newType(JSContext *cx, TypeSet *source, Type type) = 0;
|
||||
@ -223,45 +213,30 @@ enum {
|
||||
/* Mask of normal type flags on a type set. */
|
||||
TYPE_FLAG_BASE_MASK = 0x000100ff,
|
||||
|
||||
/* Flags describing the kind of type set this is. */
|
||||
|
||||
/*
|
||||
* Flag for type sets which describe stack values and are cleared on
|
||||
* analysis purges.
|
||||
*/
|
||||
TYPE_FLAG_PURGED = 0x00020000,
|
||||
|
||||
/*
|
||||
* Flag for type sets whose constraints are cleared on analysis purges.
|
||||
* This includes all temporary type sets, as well as sets in TypeScript
|
||||
* which propagate into temporary type sets.
|
||||
*/
|
||||
TYPE_FLAG_CONSTRAINTS_PURGED = 0x00040000,
|
||||
|
||||
/* Flags for type sets which are on object properties. */
|
||||
|
||||
/*
|
||||
* Whether there are subset constraints propagating the possible types
|
||||
* for this property inherited from the object's prototypes. Reset on GC.
|
||||
*/
|
||||
TYPE_FLAG_PROPAGATED_PROPERTY = 0x00080000,
|
||||
TYPE_FLAG_PROPAGATED_PROPERTY = 0x00020000,
|
||||
|
||||
/* Whether this property has ever been directly written. */
|
||||
TYPE_FLAG_OWN_PROPERTY = 0x00100000,
|
||||
TYPE_FLAG_OWN_PROPERTY = 0x00040000,
|
||||
|
||||
/*
|
||||
* Whether the property has ever been deleted or reconfigured to behave
|
||||
* differently from a normal native property (e.g. made non-writable or
|
||||
* given a scripted getter or setter).
|
||||
*/
|
||||
TYPE_FLAG_CONFIGURED_PROPERTY = 0x00200000,
|
||||
TYPE_FLAG_CONFIGURED_PROPERTY = 0x00080000,
|
||||
|
||||
/*
|
||||
* Whether the property is definitely in a particular inline slot on all
|
||||
* objects from which it has not been deleted or reconfigured. Implies
|
||||
* OWN_PROPERTY and unlike OWN/CONFIGURED property, this cannot change.
|
||||
*/
|
||||
TYPE_FLAG_DEFINITE_PROPERTY = 0x00400000,
|
||||
TYPE_FLAG_DEFINITE_PROPERTY = 0x00100000,
|
||||
|
||||
/* If the property is definite, mask and shift storing the slot. */
|
||||
TYPE_FLAG_DEFINITE_MASK = 0x0f000000,
|
||||
@ -340,9 +315,6 @@ enum {
|
||||
};
|
||||
typedef uint32_t TypeObjectFlags;
|
||||
|
||||
class StackTypeSet;
|
||||
class HeapTypeSet;
|
||||
|
||||
/* Information about the set of types associated with an lvalue. */
|
||||
class TypeSet
|
||||
{
|
||||
@ -380,12 +352,12 @@ class TypeSet
|
||||
return !!(baseFlags() & flags);
|
||||
}
|
||||
|
||||
bool ownProperty(bool configurable) const {
|
||||
bool isOwnProperty(bool configurable) const {
|
||||
return flags & (configurable ? TYPE_FLAG_CONFIGURED_PROPERTY : TYPE_FLAG_OWN_PROPERTY);
|
||||
}
|
||||
bool definiteProperty() const { return flags & TYPE_FLAG_DEFINITE_PROPERTY; }
|
||||
bool isDefiniteProperty() const { return flags & TYPE_FLAG_DEFINITE_PROPERTY; }
|
||||
unsigned definiteSlot() const {
|
||||
JS_ASSERT(definiteProperty());
|
||||
JS_ASSERT(isDefiniteProperty());
|
||||
return flags >> TYPE_FLAG_DEFINITE_SHIFT;
|
||||
}
|
||||
|
||||
@ -421,115 +393,55 @@ class TypeSet
|
||||
bool hasPropagatedProperty() { return !!(flags & TYPE_FLAG_PROPAGATED_PROPERTY); }
|
||||
void setPropagatedProperty() { flags |= TYPE_FLAG_PROPAGATED_PROPERTY; }
|
||||
|
||||
bool constraintsPurged() { return !!(flags & TYPE_FLAG_CONSTRAINTS_PURGED); }
|
||||
void setConstraintsPurged() { flags |= TYPE_FLAG_CONSTRAINTS_PURGED; }
|
||||
enum FilterKind {
|
||||
FILTER_ALL_PRIMITIVES,
|
||||
FILTER_NULL_VOID,
|
||||
FILTER_VOID
|
||||
};
|
||||
|
||||
bool purged() { return !!(flags & TYPE_FLAG_PURGED); }
|
||||
void setPurged() { flags |= TYPE_FLAG_PURGED | TYPE_FLAG_CONSTRAINTS_PURGED; }
|
||||
|
||||
inline StackTypeSet *toStackTypeSet();
|
||||
inline HeapTypeSet *toHeapTypeSet();
|
||||
|
||||
inline void addTypesToConstraint(JSContext *cx, TypeConstraint *constraint);
|
||||
/* Add specific kinds of constraints to this set. */
|
||||
inline void add(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
|
||||
|
||||
protected:
|
||||
uint32_t baseObjectCount() const {
|
||||
return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT;
|
||||
}
|
||||
inline void setBaseObjectCount(uint32_t count);
|
||||
|
||||
inline void clearObjects();
|
||||
};
|
||||
|
||||
/*
|
||||
* Type set for a stack value manipulated in a script, or the argument or
|
||||
* local types of said script. Constraints on these type sets are cleared
|
||||
* during analysis purges; the contents of the sets are implicitly frozen
|
||||
* during compilation to ensure that changes to the sets trigger recompilation
|
||||
* of the associated script.
|
||||
*/
|
||||
class StackTypeSet : public TypeSet
|
||||
{
|
||||
public:
|
||||
|
||||
/*
|
||||
* Make a type set with the specified debugging name, not embedded in
|
||||
* another structure.
|
||||
*/
|
||||
static StackTypeSet *make(JSContext *cx, const char *name);
|
||||
|
||||
/* Constraints for type inference. */
|
||||
|
||||
void addSubset(JSContext *cx, TypeSet *target);
|
||||
void addGetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
StackTypeSet *target, jsid id);
|
||||
TypeSet *target, jsid id);
|
||||
void addSetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
StackTypeSet *target, jsid id);
|
||||
TypeSet *target, jsid id);
|
||||
void addCallProperty(JSContext *cx, JSScript *script, jsbytecode *pc, jsid id);
|
||||
void addSetElement(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
StackTypeSet *objectTypes, StackTypeSet *valueTypes);
|
||||
TypeSet *objectTypes, TypeSet *valueTypes);
|
||||
void addCall(JSContext *cx, TypeCallsite *site);
|
||||
void addArith(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
TypeSet *target, TypeSet *other = NULL);
|
||||
void addTransformThis(JSContext *cx, JSScript *script, TypeSet *target);
|
||||
void addPropagateThis(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
Type type, StackTypeSet *types = NULL);
|
||||
Type type, TypeSet *types = NULL);
|
||||
void addFilterPrimitives(JSContext *cx, TypeSet *target, FilterKind filter);
|
||||
void addSubsetBarrier(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target);
|
||||
|
||||
/*
|
||||
* Constraints for JIT compilation.
|
||||
*
|
||||
* Methods for JIT compilation. These must be used when a script is
|
||||
* currently being compiled (see AutoEnterCompilation) and will add
|
||||
* constraints ensuring that if the return value change in the future due
|
||||
* to new type information, the script's jitcode will be discarded.
|
||||
* Make an type set with the specified debugging name, not embedded in
|
||||
* another structure.
|
||||
*/
|
||||
|
||||
/* Get any type tag which all values in this set must have. */
|
||||
JSValueType getKnownTypeTag();
|
||||
|
||||
bool isMagicArguments() { return getKnownTypeTag() == JSVAL_TYPE_MAGIC; }
|
||||
|
||||
/* Whether the type set contains objects with any of a set of flags. */
|
||||
bool hasObjectFlags(JSContext *cx, TypeObjectFlags flags);
|
||||
static TypeSet *make(JSContext *cx, const char *name);
|
||||
|
||||
/*
|
||||
* Get the typed array type of all objects in this set. Returns
|
||||
* TypedArray::TYPE_MAX if the set contains different array types.
|
||||
* Methods for JIT compilation. If a script is currently being compiled
|
||||
* (see AutoEnterCompilation) these will add constraints ensuring that if
|
||||
* the return value change in the future due to new type information, the
|
||||
* currently compiled script will be marked for recompilation.
|
||||
*/
|
||||
int getTypedArrayType();
|
||||
|
||||
/* Get the single value which can appear in this type set, otherwise NULL. */
|
||||
JSObject *getSingleton();
|
||||
|
||||
/* Whether any objects in the type set needs a barrier on id. */
|
||||
bool propertyNeedsBarrier(JSContext *cx, jsid id);
|
||||
};
|
||||
|
||||
/*
|
||||
* Type set for a property of a TypeObject, or for the return value or property
|
||||
* read inputs of a script. In contrast with stack type sets, constraints on
|
||||
* these sets are not cleared during analysis purges, and are not implicitly
|
||||
* frozen during compilation.
|
||||
*/
|
||||
class HeapTypeSet : public TypeSet
|
||||
{
|
||||
public:
|
||||
|
||||
/* Constraints for type inference. */
|
||||
|
||||
void addSubset(JSContext *cx, TypeSet *target);
|
||||
void addGetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
StackTypeSet *target, jsid id);
|
||||
void addCallProperty(JSContext *cx, JSScript *script, jsbytecode *pc, jsid id);
|
||||
void addFilterPrimitives(JSContext *cx, TypeSet *target);
|
||||
void addSubsetBarrier(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target);
|
||||
|
||||
/* Constraints for JIT compilation. */
|
||||
|
||||
/* Completely freeze the contents of this type set. */
|
||||
void addFreeze(JSContext *cx);
|
||||
|
||||
/* Get any type tag which all values in this set must have. */
|
||||
JSValueType getKnownTypeTag(JSContext *cx);
|
||||
|
||||
bool isMagicArguments(JSContext *cx) { return getKnownTypeTag(cx) == JSVAL_TYPE_MAGIC; }
|
||||
|
||||
/* Whether the type set or a particular object has any of a set of flags. */
|
||||
bool hasObjectFlags(JSContext *cx, TypeObjectFlags flags);
|
||||
static bool HasObjectFlags(JSContext *cx, TypeObject *object, TypeObjectFlags flags);
|
||||
|
||||
/*
|
||||
* Watch for a generic object state change on a type object. This currently
|
||||
@ -538,9 +450,6 @@ class HeapTypeSet : public TypeSet
|
||||
*/
|
||||
static void WatchObjectStateChange(JSContext *cx, TypeObject *object);
|
||||
|
||||
/* Whether an object has any of a set of flags. */
|
||||
static bool HasObjectFlags(JSContext *cx, TypeObject *object, TypeObjectFlags flags);
|
||||
|
||||
/*
|
||||
* For type sets on a property, return true if the property has any 'own'
|
||||
* values assigned. If configurable is set, return 'true' if the property
|
||||
@ -556,30 +465,33 @@ class HeapTypeSet : public TypeSet
|
||||
/* Get whether this type set is known to be a subset of other. */
|
||||
bool knownSubset(JSContext *cx, TypeSet *other);
|
||||
|
||||
/*
|
||||
* Get the typed array type of all objects in this set. Returns
|
||||
* TypedArray::TYPE_MAX if the set contains different array types.
|
||||
*/
|
||||
int getTypedArrayType(JSContext *cx);
|
||||
|
||||
/* Get the single value which can appear in this type set, otherwise NULL. */
|
||||
JSObject *getSingleton(JSContext *cx);
|
||||
JSObject *getSingleton(JSContext *cx, bool freeze = true);
|
||||
|
||||
inline void clearObjects();
|
||||
|
||||
/*
|
||||
* Whether a location with this TypeSet needs a write barrier (i.e., whether
|
||||
* it can hold GC things). The type set is frozen if no barrier is needed.
|
||||
*/
|
||||
bool needsBarrier(JSContext *cx);
|
||||
|
||||
/* The type set is frozen if no barrier is needed. */
|
||||
bool propertyNeedsBarrier(JSContext *cx, jsid id);
|
||||
|
||||
private:
|
||||
uint32_t baseObjectCount() const {
|
||||
return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT;
|
||||
}
|
||||
inline void setBaseObjectCount(uint32_t count);
|
||||
};
|
||||
|
||||
inline StackTypeSet *
|
||||
TypeSet::toStackTypeSet()
|
||||
{
|
||||
JS_ASSERT(constraintsPurged());
|
||||
return (StackTypeSet *) this;
|
||||
}
|
||||
|
||||
inline HeapTypeSet *
|
||||
TypeSet::toHeapTypeSet()
|
||||
{
|
||||
JS_ASSERT(!constraintsPurged());
|
||||
return (HeapTypeSet *) this;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handler which persists information about dynamic types pushed within a
|
||||
* script which can affect its behavior and are not covered by JOF_TYPESET ops,
|
||||
@ -689,7 +601,7 @@ struct Property
|
||||
HeapId id;
|
||||
|
||||
/* Possible types for this property, including types inherited from prototypes. */
|
||||
HeapTypeSet types;
|
||||
TypeSet types;
|
||||
|
||||
inline Property(jsid id);
|
||||
inline Property(const Property &o);
|
||||
@ -881,10 +793,10 @@ struct TypeObject : gc::Cell
|
||||
* assignment, and the own types of the property will be used instead of
|
||||
* aggregate types.
|
||||
*/
|
||||
inline HeapTypeSet *getProperty(JSContext *cx, jsid id, bool assign);
|
||||
inline TypeSet *getProperty(JSContext *cx, jsid id, bool assign);
|
||||
|
||||
/* Get a property only if it already exists. */
|
||||
inline HeapTypeSet *maybeGetProperty(JSContext *cx, jsid id);
|
||||
inline TypeSet *maybeGetProperty(JSContext *cx, jsid id);
|
||||
|
||||
inline unsigned getPropertyCount();
|
||||
inline Property *getProperty(unsigned i);
|
||||
@ -989,13 +901,13 @@ struct TypeCallsite
|
||||
|
||||
/* Types of each argument to the call. */
|
||||
unsigned argumentCount;
|
||||
StackTypeSet **argumentTypes;
|
||||
TypeSet **argumentTypes;
|
||||
|
||||
/* Types of the this variable. */
|
||||
StackTypeSet *thisTypes;
|
||||
TypeSet *thisTypes;
|
||||
|
||||
/* Type set receiving the return value of this call. */
|
||||
StackTypeSet *returnTypes;
|
||||
TypeSet *returnTypes;
|
||||
|
||||
inline TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
bool isNew, unsigned argumentCount);
|
||||
@ -1013,25 +925,18 @@ class TypeScript
|
||||
/* Dynamic types generated at points within this script. */
|
||||
TypeResult *dynamicList;
|
||||
|
||||
/*
|
||||
* Array of type sets storing the possible inputs to property reads.
|
||||
* Generated the first time the script is analyzed by inference and kept
|
||||
* after analysis purges.
|
||||
*/
|
||||
HeapTypeSet *propertyReadTypes;
|
||||
|
||||
/* Array of type type sets for variables and JOF_TYPESET ops. */
|
||||
TypeSet *typeArray() { return (TypeSet *) (uintptr_t(this) + sizeof(TypeScript)); }
|
||||
|
||||
static inline unsigned NumTypeSets(JSScript *script);
|
||||
|
||||
static inline HeapTypeSet *ReturnTypes(JSScript *script);
|
||||
static inline StackTypeSet *ThisTypes(JSScript *script);
|
||||
static inline StackTypeSet *ArgTypes(JSScript *script, unsigned i);
|
||||
static inline StackTypeSet *LocalTypes(JSScript *script, unsigned i);
|
||||
static inline TypeSet *ReturnTypes(JSScript *script);
|
||||
static inline TypeSet *ThisTypes(JSScript *script);
|
||||
static inline TypeSet *ArgTypes(JSScript *script, unsigned i);
|
||||
static inline TypeSet *LocalTypes(JSScript *script, unsigned i);
|
||||
|
||||
/* Follows slot layout in jsanalyze.h, can get this/arg/local type sets. */
|
||||
static inline StackTypeSet *SlotTypes(JSScript *script, unsigned slot);
|
||||
static inline TypeSet *SlotTypes(JSScript *script, unsigned slot);
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Check that correct types were inferred for the values pushed by this bytecode. */
|
||||
@ -1079,9 +984,6 @@ class TypeScript
|
||||
static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type);
|
||||
static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value);
|
||||
|
||||
static void AddFreezeConstraints(JSContext *cx, JSScript *script);
|
||||
static void Purge(JSContext *cx, JSScript *script);
|
||||
|
||||
static void Sweep(FreeOp *fop, JSScript *script);
|
||||
void destroy();
|
||||
};
|
||||
@ -1264,9 +1166,6 @@ struct TypeCompartment
|
||||
|
||||
void sweep(FreeOp *fop);
|
||||
void sweepCompilerOutputs(FreeOp *fop);
|
||||
|
||||
void maybePurgeAnalysis(JSContext *cx, bool force = false);
|
||||
|
||||
void finalizeObjects();
|
||||
};
|
||||
|
||||
|
@ -602,18 +602,16 @@ TypeScript::NumTypeSets(JSScript *script)
|
||||
return script->nTypeSets + analyze::TotalSlots(script);
|
||||
}
|
||||
|
||||
/* static */ inline HeapTypeSet *
|
||||
/* static */ inline TypeSet *
|
||||
TypeScript::ReturnTypes(JSScript *script)
|
||||
{
|
||||
TypeSet *types = script->types->typeArray() + script->nTypeSets + js::analyze::CalleeSlot();
|
||||
return types->toHeapTypeSet();
|
||||
return script->types->typeArray() + script->nTypeSets + js::analyze::CalleeSlot();
|
||||
}
|
||||
|
||||
/* static */ inline StackTypeSet *
|
||||
/* static */ inline TypeSet *
|
||||
TypeScript::ThisTypes(JSScript *script)
|
||||
{
|
||||
TypeSet *types = script->types->typeArray() + script->nTypeSets + js::analyze::ThisSlot();
|
||||
return types->toStackTypeSet();
|
||||
return script->types->typeArray() + script->nTypeSets + js::analyze::ThisSlot();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -622,28 +620,25 @@ TypeScript::ThisTypes(JSScript *script)
|
||||
* or undefined for localTypes) and not types from subsequent assignments.
|
||||
*/
|
||||
|
||||
/* static */ inline StackTypeSet *
|
||||
/* static */ inline TypeSet *
|
||||
TypeScript::ArgTypes(JSScript *script, unsigned i)
|
||||
{
|
||||
JS_ASSERT(i < script->function()->nargs);
|
||||
TypeSet *types = script->types->typeArray() + script->nTypeSets + js::analyze::ArgSlot(i);
|
||||
return types->toStackTypeSet();
|
||||
return script->types->typeArray() + script->nTypeSets + js::analyze::ArgSlot(i);
|
||||
}
|
||||
|
||||
/* static */ inline StackTypeSet *
|
||||
/* static */ inline TypeSet *
|
||||
TypeScript::LocalTypes(JSScript *script, unsigned i)
|
||||
{
|
||||
JS_ASSERT(i < script->nfixed);
|
||||
TypeSet *types = script->types->typeArray() + script->nTypeSets + js::analyze::LocalSlot(script, i);
|
||||
return types->toStackTypeSet();
|
||||
return script->types->typeArray() + script->nTypeSets + js::analyze::LocalSlot(script, i);
|
||||
}
|
||||
|
||||
/* static */ inline StackTypeSet *
|
||||
/* static */ inline TypeSet *
|
||||
TypeScript::SlotTypes(JSScript *script, unsigned slot)
|
||||
{
|
||||
JS_ASSERT(slot < js::analyze::TotalSlots(script));
|
||||
TypeSet *types = script->types->typeArray() + script->nTypeSets + slot;
|
||||
return types->toStackTypeSet();
|
||||
return script->types->typeArray() + script->nTypeSets + slot;
|
||||
}
|
||||
|
||||
/* static */ inline TypeObject *
|
||||
@ -1002,7 +997,7 @@ HashKey(T v)
|
||||
*/
|
||||
template <class T, class U, class KEY>
|
||||
static U **
|
||||
HashSetInsertTry(LifoAlloc &alloc, U **&values, unsigned &count, T key)
|
||||
HashSetInsertTry(JSCompartment *compartment, U **&values, unsigned &count, T key)
|
||||
{
|
||||
unsigned capacity = HashSetCapacity(count);
|
||||
unsigned insertpos = HashKey<T,KEY>(key) & (capacity - 1);
|
||||
@ -1026,7 +1021,7 @@ HashSetInsertTry(LifoAlloc &alloc, U **&values, unsigned &count, T key)
|
||||
return &values[insertpos];
|
||||
}
|
||||
|
||||
U **newValues = alloc.newArray<U*>(newCapacity);
|
||||
U **newValues = compartment->typeLifoAlloc.newArray<U*>(newCapacity);
|
||||
if (!newValues)
|
||||
return NULL;
|
||||
PodZero(newValues, newCapacity);
|
||||
@ -1054,7 +1049,7 @@ HashSetInsertTry(LifoAlloc &alloc, U **&values, unsigned &count, T key)
|
||||
*/
|
||||
template <class T, class U, class KEY>
|
||||
static inline U **
|
||||
HashSetInsert(LifoAlloc &alloc, U **&values, unsigned &count, T key)
|
||||
HashSetInsert(JSCompartment *compartment, U **&values, unsigned &count, T key)
|
||||
{
|
||||
if (count == 0) {
|
||||
JS_ASSERT(values == NULL);
|
||||
@ -1067,7 +1062,7 @@ HashSetInsert(LifoAlloc &alloc, U **&values, unsigned &count, T key)
|
||||
if (KEY::getKey(oldData) == key)
|
||||
return (U **) &values;
|
||||
|
||||
values = alloc.newArray<U*>(SET_ARRAY_SIZE);
|
||||
values = compartment->typeLifoAlloc.newArray<U*>(SET_ARRAY_SIZE);
|
||||
if (!values) {
|
||||
values = (U **) oldData;
|
||||
return NULL;
|
||||
@ -1091,7 +1086,7 @@ HashSetInsert(LifoAlloc &alloc, U **&values, unsigned &count, T key)
|
||||
}
|
||||
}
|
||||
|
||||
return HashSetInsertTry<T,U,KEY>(alloc, values, count, key);
|
||||
return HashSetInsertTry<T,U,KEY>(compartment, values, count, key);
|
||||
}
|
||||
|
||||
/* Lookup an entry in a hash set, return NULL if it does not exist. */
|
||||
@ -1213,14 +1208,10 @@ TypeSet::addType(JSContext *cx, Type type)
|
||||
return;
|
||||
if (type.isAnyObject())
|
||||
goto unknownObject;
|
||||
|
||||
LifoAlloc &alloc =
|
||||
purged() ? cx->compartment->analysisLifoAlloc : cx->compartment->typeLifoAlloc;
|
||||
|
||||
uint32_t objectCount = baseObjectCount();
|
||||
TypeObjectKey *object = type.objectKey();
|
||||
TypeObjectKey **pentry = HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
|
||||
(alloc, objectSet, objectCount, object);
|
||||
(cx->compartment, objectSet, objectCount, object);
|
||||
if (!pentry) {
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
@ -1335,7 +1326,7 @@ TypeCallsite::TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
thisTypes(NULL), returnTypes(NULL)
|
||||
{
|
||||
/* Caller must check for failure. */
|
||||
argumentTypes = cx->analysisLifoAlloc().newArray<StackTypeSet*>(argumentCount);
|
||||
argumentTypes = cx->typeLifoAlloc().newArray<TypeSet*>(argumentCount);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
@ -1373,7 +1364,7 @@ TypeObject::setBasePropertyCount(uint32_t count)
|
||||
| (count << OBJECT_FLAG_PROPERTY_COUNT_SHIFT);
|
||||
}
|
||||
|
||||
inline HeapTypeSet *
|
||||
inline TypeSet *
|
||||
TypeObject::getProperty(JSContext *cx, jsid id, bool assign)
|
||||
{
|
||||
JS_ASSERT(cx->compartment->activeInference);
|
||||
@ -1383,7 +1374,7 @@ TypeObject::getProperty(JSContext *cx, jsid id, bool assign)
|
||||
|
||||
uint32_t propertyCount = basePropertyCount();
|
||||
Property **pprop = HashSetInsert<jsid,Property,Property>
|
||||
(cx->compartment->typeLifoAlloc, propertySet, propertyCount, id);
|
||||
(cx->compartment, propertySet, propertyCount, id);
|
||||
if (!pprop) {
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
return NULL;
|
||||
@ -1398,25 +1389,15 @@ TypeObject::getProperty(JSContext *cx, jsid id, bool assign)
|
||||
}
|
||||
if (propertyCount == OBJECT_FLAG_PROPERTY_COUNT_LIMIT) {
|
||||
markUnknown(cx);
|
||||
|
||||
/*
|
||||
* Return an arbitrary property in the object, as all have unknown
|
||||
* type and are treated as configured.
|
||||
*/
|
||||
unsigned count = getPropertyCount();
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
if (Property *prop = getProperty(i))
|
||||
return &prop->types;
|
||||
}
|
||||
|
||||
JS_NOT_REACHED("Missing property");
|
||||
return NULL;
|
||||
TypeSet *types = TypeSet::make(cx, "propertyOverflow");
|
||||
types->addType(cx, Type::UnknownType());
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
HeapTypeSet *types = &(*pprop)->types;
|
||||
TypeSet *types = &(*pprop)->types;
|
||||
|
||||
if (assign && !types->ownProperty(false)) {
|
||||
if (assign && !types->isOwnProperty(false)) {
|
||||
/*
|
||||
* Normally, we just want to set the property as being an own property
|
||||
* when we got a set to it. The exception is when the set is actually
|
||||
@ -1450,7 +1431,7 @@ TypeObject::getProperty(JSContext *cx, jsid id, bool assign)
|
||||
return types;
|
||||
}
|
||||
|
||||
inline HeapTypeSet *
|
||||
inline TypeSet *
|
||||
TypeObject::maybeGetProperty(JSContext *cx, jsid id)
|
||||
{
|
||||
JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
|
||||
@ -1643,13 +1624,6 @@ JSScript::clearAnalysis()
|
||||
types->analysis = NULL;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSScript::clearPropertyReadTypes()
|
||||
{
|
||||
if (types && types->propertyReadTypes)
|
||||
types->propertyReadTypes = NULL;
|
||||
}
|
||||
|
||||
inline void
|
||||
js::analyze::ScriptAnalysis::addPushedType(JSContext *cx, uint32_t offset, uint32_t which,
|
||||
js::types::Type type)
|
||||
|
@ -469,9 +469,6 @@ struct JSScript : public js::gc::Cell
|
||||
JSCompartment::scriptCountsMap */
|
||||
bool hasDebugScript:1; /* script has an entry in
|
||||
JSCompartment::debugScriptMap */
|
||||
bool hasFreezeConstraints:1; /* freeze constraints for stack
|
||||
* type sets have been generated */
|
||||
|
||||
private:
|
||||
/* See comments below. */
|
||||
bool argsHasVarBinding_:1;
|
||||
@ -578,8 +575,6 @@ struct JSScript : public js::gc::Cell
|
||||
inline void clearAnalysis();
|
||||
inline js::analyze::ScriptAnalysis *analysis();
|
||||
|
||||
inline void clearPropertyReadTypes();
|
||||
|
||||
inline bool hasGlobal() const;
|
||||
inline bool hasClearedGlobal() const;
|
||||
|
||||
|
@ -83,8 +83,6 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript,
|
||||
doubleList(CompilerAllocPolicy(cx, *thisFromCtor())),
|
||||
rootedTemplates(CompilerAllocPolicy(cx, *thisFromCtor())),
|
||||
rootedRegExps(CompilerAllocPolicy(cx, *thisFromCtor())),
|
||||
monitoredBytecodes(CompilerAllocPolicy(cx, *thisFromCtor())),
|
||||
typeBarrierBytecodes(CompilerAllocPolicy(cx, *thisFromCtor())),
|
||||
fixedIntToDoubleEntries(CompilerAllocPolicy(cx, *thisFromCtor())),
|
||||
fixedDoubleToAnyEntries(CompilerAllocPolicy(cx, *thisFromCtor())),
|
||||
jumpTables(CompilerAllocPolicy(cx, *thisFromCtor())),
|
||||
@ -227,9 +225,9 @@ mjit::Compiler::scanInlineCalls(uint32_t index, uint32_t depth)
|
||||
continue;
|
||||
|
||||
uint32_t argc = GET_ARGC(pc);
|
||||
types::StackTypeSet *calleeTypes = analysis->poppedTypes(pc, argc + 1);
|
||||
types::TypeSet *calleeTypes = analysis->poppedTypes(pc, argc + 1);
|
||||
|
||||
if (calleeTypes->getKnownTypeTag() != JSVAL_TYPE_OBJECT)
|
||||
if (calleeTypes->getKnownTypeTag(cx) != JSVAL_TYPE_OBJECT)
|
||||
continue;
|
||||
|
||||
if (calleeTypes->getObjectCount() >= INLINE_SITE_LIMIT)
|
||||
@ -334,19 +332,12 @@ mjit::Compiler::scanInlineCalls(uint32_t index, uint32_t depth)
|
||||
break;
|
||||
}
|
||||
|
||||
if (types::HeapTypeSet::HasObjectFlags(cx, fun->getType(cx),
|
||||
types::OBJECT_FLAG_UNINLINEABLE)) {
|
||||
if (types::TypeSet::HasObjectFlags(cx, fun->getType(cx),
|
||||
types::OBJECT_FLAG_UNINLINEABLE)) {
|
||||
okay = false;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Watch for a generic state change in the callee's type, so that
|
||||
* the outer script will be recompiled if any type information
|
||||
* changes in stack values within the callee.
|
||||
*/
|
||||
types::HeapTypeSet::WatchObjectStateChange(cx, fun->getType(cx));
|
||||
|
||||
/*
|
||||
* Don't inline scripts which use 'this' if it is possible they
|
||||
* could be called with a 'this' value requiring wrapping. During
|
||||
@ -354,7 +345,7 @@ mjit::Compiler::scanInlineCalls(uint32_t index, uint32_t depth)
|
||||
* caller.
|
||||
*/
|
||||
if (script->analysis()->usesThisValue() &&
|
||||
types::TypeScript::ThisTypes(script)->getKnownTypeTag() != JSVAL_TYPE_OBJECT) {
|
||||
types::TypeScript::ThisTypes(script)->getKnownTypeTag(cx) != JSVAL_TYPE_OBJECT) {
|
||||
okay = false;
|
||||
break;
|
||||
}
|
||||
@ -362,6 +353,8 @@ mjit::Compiler::scanInlineCalls(uint32_t index, uint32_t depth)
|
||||
if (!okay)
|
||||
continue;
|
||||
|
||||
calleeTypes->addFreeze(cx);
|
||||
|
||||
/*
|
||||
* Add the inline frames to the cross script SSA. We will pick these
|
||||
* back up when compiling the call site.
|
||||
@ -1015,13 +1008,6 @@ mjit::CanMethodJIT(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
status = cc.compile();
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we have hit the threshold for purging analysis data. This is
|
||||
* done after compilation, rather than after another analysis stage, to
|
||||
* ensure we don't throw away the work just performed.
|
||||
*/
|
||||
cx->compartment->types.maybePurgeAnalysis(cx);
|
||||
|
||||
if (status == Compile_Okay) {
|
||||
/*
|
||||
* Compiling a script can occasionally trigger its own recompilation,
|
||||
@ -1197,7 +1183,7 @@ mjit::Compiler::ensureDoubleArguments()
|
||||
/* Convert integer arguments which were inferred as (int|double) to doubles. */
|
||||
for (uint32_t i = 0; script->function() && i < script->function()->nargs; i++) {
|
||||
uint32_t slot = ArgSlot(i);
|
||||
if (a->varTypes[slot].getTypeTag() == JSVAL_TYPE_DOUBLE && analysis->trackSlot(slot))
|
||||
if (a->varTypes[slot].getTypeTag(cx) == JSVAL_TYPE_DOUBLE && analysis->trackSlot(slot))
|
||||
frame.ensureDouble(frame.getArg(i));
|
||||
}
|
||||
}
|
||||
@ -1345,8 +1331,6 @@ mjit::Compiler::finishThisUp()
|
||||
sizeof(CallSite) * callSites.length() +
|
||||
sizeof(JSObject*) * rootedTemplates.length() +
|
||||
sizeof(RegExpShared*) * rootedRegExps.length() +
|
||||
sizeof(uint32_t) * monitoredBytecodes.length() +
|
||||
sizeof(uint32_t) * typeBarrierBytecodes.length() +
|
||||
#if defined JS_MONOIC
|
||||
sizeof(ic::GetGlobalNameIC) * getGlobalNames.length() +
|
||||
sizeof(ic::SetGlobalNameIC) * setGlobalNames.length() +
|
||||
@ -1490,18 +1474,6 @@ mjit::Compiler::finishThisUp()
|
||||
jitRootedRegExps[i]->incRef();
|
||||
}
|
||||
|
||||
uint32_t *jitMonitoredBytecodes = (uint32_t *)cursor;
|
||||
chunk->nMonitoredBytecodes = monitoredBytecodes.length();
|
||||
cursor += sizeof(uint32_t) * chunk->nMonitoredBytecodes;
|
||||
for (size_t i = 0; i < chunk->nMonitoredBytecodes; i++)
|
||||
jitMonitoredBytecodes[i] = monitoredBytecodes[i];
|
||||
|
||||
uint32_t *jitTypeBarrierBytecodes = (uint32_t *)cursor;
|
||||
chunk->nTypeBarrierBytecodes = typeBarrierBytecodes.length();
|
||||
cursor += sizeof(uint32_t) * chunk->nTypeBarrierBytecodes;
|
||||
for (size_t i = 0; i < chunk->nTypeBarrierBytecodes; i++)
|
||||
jitTypeBarrierBytecodes[i] = typeBarrierBytecodes[i];
|
||||
|
||||
#if defined JS_MONOIC
|
||||
if (chunkIndex == 0 && script->function()) {
|
||||
JS_ASSERT(jit->argsCheckPool == NULL);
|
||||
@ -2119,7 +2091,7 @@ mjit::Compiler::generateMethod()
|
||||
if (newv->value.kind() == SSAValue::PHI &&
|
||||
newv->value.phiOffset() == uint32_t(PC - script->code) &&
|
||||
analysis->trackSlot(newv->slot) &&
|
||||
a->varTypes[newv->slot].getTypeTag() == JSVAL_TYPE_DOUBLE) {
|
||||
a->varTypes[newv->slot].getTypeTag(cx) == JSVAL_TYPE_DOUBLE) {
|
||||
FrameEntry *fe = frame.getSlotEntry(newv->slot);
|
||||
masm.ensureInMemoryDouble(frame.addressOf(fe));
|
||||
}
|
||||
@ -2141,7 +2113,7 @@ mjit::Compiler::generateMethod()
|
||||
jsbytecode *backedge = script->code + analysis->getLoop(PC)->backedge;
|
||||
if (!bytecodeInChunk(backedge)){
|
||||
for (uint32_t slot = ArgSlot(0); slot < TotalSlots(script); slot++) {
|
||||
if (a->varTypes[slot].getTypeTag() == JSVAL_TYPE_DOUBLE) {
|
||||
if (a->varTypes[slot].getTypeTag(cx) == JSVAL_TYPE_DOUBLE) {
|
||||
FrameEntry *fe = frame.getSlotEntry(slot);
|
||||
masm.ensureInMemoryDouble(frame.addressOf(fe));
|
||||
}
|
||||
@ -3534,9 +3506,9 @@ mjit::Compiler::updateElemCounts(jsbytecode *pc, FrameEntry *obj, FrameEntry *id
|
||||
masm.bumpCount(&counts.get(count), reg);
|
||||
|
||||
if (obj->mightBeType(JSVAL_TYPE_OBJECT)) {
|
||||
types::StackTypeSet *types = frame.extra(obj).types;
|
||||
types::TypeSet *types = frame.extra(obj).types;
|
||||
if (types && !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_TYPED_ARRAY) &&
|
||||
types->getTypedArrayType() != TypedArray::TYPE_MAX) {
|
||||
types->getTypedArrayType(cx) != TypedArray::TYPE_MAX) {
|
||||
count = PCCounts::ELEM_OBJECT_TYPED;
|
||||
} else if (types && !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY)) {
|
||||
if (!types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED_ARRAY))
|
||||
@ -4258,13 +4230,6 @@ mjit::Compiler::inlineCallHelper(uint32_t argc, bool callingNew, FrameSize &call
|
||||
|
||||
callIC.typeMonitored = monitored(PC) || hasTypeBarriers(PC);
|
||||
|
||||
if (script == outerScript) {
|
||||
if (monitored(PC))
|
||||
monitoredBytecodes.append(PC - script->code);
|
||||
if (hasTypeBarriers(PC))
|
||||
typeBarrierBytecodes.append(PC - script->code);
|
||||
}
|
||||
|
||||
/* Test the type if necessary. Failing this always takes a really slow path. */
|
||||
MaybeJump notObjectJump;
|
||||
if (icCalleeType.isSet())
|
||||
@ -4879,7 +4844,7 @@ mjit::Compiler::jsop_getprop(PropertyName *name, JSValueType knownType,
|
||||
/* Handle lenth accesses of optimize 'arguments'. */
|
||||
if (name == cx->runtime->atomState.lengthAtom &&
|
||||
cx->typeInferenceEnabled() &&
|
||||
analysis->poppedTypes(PC, 0)->isMagicArguments() &&
|
||||
analysis->poppedTypes(PC, 0)->isMagicArguments(cx) &&
|
||||
knownPushedType(0) == JSVAL_TYPE_INT32)
|
||||
{
|
||||
frame.pop();
|
||||
@ -4908,7 +4873,7 @@ mjit::Compiler::jsop_getprop(PropertyName *name, JSValueType knownType,
|
||||
}
|
||||
}
|
||||
|
||||
types::StackTypeSet *types = analysis->poppedTypes(PC, 0);
|
||||
types::TypeSet *types = analysis->poppedTypes(PC, 0);
|
||||
|
||||
/*
|
||||
* Check if we are accessing the 'length' property of a known dense array.
|
||||
@ -5038,11 +5003,12 @@ mjit::Compiler::jsop_getprop(PropertyName *name, JSValueType knownType,
|
||||
id == types::MakeTypeId(cx, id)) {
|
||||
JS_ASSERT(!forPrototype);
|
||||
types::TypeObject *object = types->getTypeObject(0);
|
||||
types::HeapTypeSet *propertyTypes = object->getProperty(cx, id, false);
|
||||
types::TypeSet *propertyTypes = object->getProperty(cx, id, false);
|
||||
if (!propertyTypes)
|
||||
return false;
|
||||
if (propertyTypes->definiteProperty() &&
|
||||
if (propertyTypes->isDefiniteProperty() &&
|
||||
!propertyTypes->isOwnProperty(cx, object, true)) {
|
||||
types->addFreeze(cx);
|
||||
uint32_t slot = propertyTypes->definiteSlot();
|
||||
bool isObject = top->isTypeKnown();
|
||||
if (!isObject) {
|
||||
@ -5241,11 +5207,11 @@ mjit::Compiler::testSingletonPropertyTypes(FrameEntry *top, HandleId id, bool *t
|
||||
{
|
||||
*testObject = false;
|
||||
|
||||
types::StackTypeSet *types = frame.extra(top).types;
|
||||
types::TypeSet *types = frame.extra(top).types;
|
||||
if (!types || types->unknownObject())
|
||||
return false;
|
||||
|
||||
RootedObject singleton(cx, types->getSingleton());
|
||||
RootedObject singleton(cx, types->getSingleton(cx));
|
||||
if (singleton)
|
||||
return testSingletonProperty(singleton, id);
|
||||
|
||||
@ -5253,7 +5219,7 @@ mjit::Compiler::testSingletonPropertyTypes(FrameEntry *top, HandleId id, bool *t
|
||||
return false;
|
||||
|
||||
JSProtoKey key;
|
||||
JSValueType type = types->getKnownTypeTag();
|
||||
JSValueType type = types->getKnownTypeTag(cx);
|
||||
switch (type) {
|
||||
case JSVAL_TYPE_STRING:
|
||||
key = JSProto_String;
|
||||
@ -5277,6 +5243,7 @@ mjit::Compiler::testSingletonPropertyTypes(FrameEntry *top, HandleId id, bool *t
|
||||
Rooted<JSObject*> proto(cx, object->proto);
|
||||
if (!testSingletonProperty(proto, id))
|
||||
return false;
|
||||
types->addFreeze(cx);
|
||||
|
||||
/* If we don't know this is an object, we will need a test. */
|
||||
*testObject = (type != JSVAL_TYPE_OBJECT) && !top->isTypeKnown();
|
||||
@ -5327,6 +5294,8 @@ mjit::Compiler::jsop_getprop_dispatch(PropertyName *name)
|
||||
if (objTypes->unknownObject() || objTypes->getObjectCount() == 0)
|
||||
return false;
|
||||
|
||||
pushedTypes->addFreeze(cx);
|
||||
|
||||
/* Map each type in the object to the resulting pushed value. */
|
||||
Vector<JSObject *> results(CompilerAllocPolicy(cx, *this));
|
||||
|
||||
@ -5345,7 +5314,7 @@ mjit::Compiler::jsop_getprop_dispatch(PropertyName *name)
|
||||
}
|
||||
if (object->unknownProperties() || !object->proto)
|
||||
return false;
|
||||
types::HeapTypeSet *ownTypes = object->getProperty(cx, id, false);
|
||||
types::TypeSet *ownTypes = object->getProperty(cx, id, false);
|
||||
if (ownTypes->isOwnProperty(cx, object, false))
|
||||
return false;
|
||||
|
||||
@ -5355,7 +5324,7 @@ mjit::Compiler::jsop_getprop_dispatch(PropertyName *name)
|
||||
|
||||
if (proto->getType(cx)->unknownProperties())
|
||||
return false;
|
||||
types::HeapTypeSet *protoTypes = proto->type()->getProperty(cx, id, false);
|
||||
types::TypeSet *protoTypes = proto->type()->getProperty(cx, id, false);
|
||||
if (!protoTypes)
|
||||
return false;
|
||||
JSObject *singleton = protoTypes->getSingleton(cx);
|
||||
@ -5369,6 +5338,8 @@ mjit::Compiler::jsop_getprop_dispatch(PropertyName *name)
|
||||
if (oomInVector)
|
||||
return false;
|
||||
|
||||
objTypes->addFreeze(cx);
|
||||
|
||||
/* Done filtering, now generate code which dispatches on the type. */
|
||||
|
||||
frame.forgetMismatchedObject(top);
|
||||
@ -5459,7 +5430,7 @@ mjit::Compiler::jsop_setprop(PropertyName *name, bool popGuaranteed)
|
||||
* always has the property in a particular inline slot.
|
||||
*/
|
||||
jsid id = NameToId(name);
|
||||
types::StackTypeSet *types = frame.extra(lhs).types;
|
||||
types::TypeSet *types = frame.extra(lhs).types;
|
||||
if (JSOp(*PC) == JSOP_SETPROP && id == types::MakeTypeId(cx, id) &&
|
||||
types && !types->unknownObject() &&
|
||||
types->getObjectCount() == 1 &&
|
||||
@ -5467,11 +5438,12 @@ mjit::Compiler::jsop_setprop(PropertyName *name, bool popGuaranteed)
|
||||
!types->getTypeObject(0)->unknownProperties())
|
||||
{
|
||||
types::TypeObject *object = types->getTypeObject(0);
|
||||
types::HeapTypeSet *propertyTypes = object->getProperty(cx, id, false);
|
||||
types::TypeSet *propertyTypes = object->getProperty(cx, id, false);
|
||||
if (!propertyTypes)
|
||||
return false;
|
||||
if (propertyTypes->definiteProperty() &&
|
||||
if (propertyTypes->isDefiniteProperty() &&
|
||||
!propertyTypes->isOwnProperty(cx, object, true)) {
|
||||
types->addFreeze(cx);
|
||||
uint32_t slot = propertyTypes->definiteSlot();
|
||||
RegisterID reg = frame.tempRegForData(lhs);
|
||||
frame.pinReg(reg);
|
||||
@ -5525,11 +5497,19 @@ mjit::Compiler::jsop_setprop(PropertyName *name, bool popGuaranteed)
|
||||
pic.name = name;
|
||||
|
||||
if (monitored(PC)) {
|
||||
if (script == outerScript)
|
||||
monitoredBytecodes.append(PC - script->code);
|
||||
pic.typeMonitored = true;
|
||||
types::TypeSet *types = frame.extra(rhs).types;
|
||||
if (!types) {
|
||||
/* Handle FORNAME and other compound opcodes. Yuck. */
|
||||
types = types::TypeSet::make(cx, "unknownRHS");
|
||||
if (!types)
|
||||
return false;
|
||||
types->addType(cx, types::Type::UnknownType());
|
||||
}
|
||||
pic.rhsTypes = types;
|
||||
} else {
|
||||
pic.typeMonitored = false;
|
||||
pic.rhsTypes = NULL;
|
||||
}
|
||||
|
||||
RESERVE_IC_SPACE(masm);
|
||||
@ -5965,7 +5945,7 @@ mjit::Compiler::jsop_this()
|
||||
}
|
||||
|
||||
JSValueType type = cx->typeInferenceEnabled()
|
||||
? types::TypeScript::ThisTypes(script)->getKnownTypeTag()
|
||||
? types::TypeScript::ThisTypes(script)->getKnownTypeTag(cx)
|
||||
: JSVAL_TYPE_UNKNOWN;
|
||||
if (type != JSVAL_TYPE_OBJECT) {
|
||||
Jump notObj = frame.testObject(Assembler::NotEqual, thisFe);
|
||||
@ -6312,7 +6292,7 @@ mjit::Compiler::jsop_getgname(uint32_t index)
|
||||
JSValueType type = knownPushedType(0);
|
||||
if (cx->typeInferenceEnabled() && globalObj->isGlobal() && id == types::MakeTypeId(cx, id) &&
|
||||
!globalObj->getType(cx)->unknownProperties()) {
|
||||
types::HeapTypeSet *propertyTypes = globalObj->getType(cx)->getProperty(cx, id, false);
|
||||
types::TypeSet *propertyTypes = globalObj->getType(cx)->getProperty(cx, id, false);
|
||||
if (!propertyTypes)
|
||||
return false;
|
||||
|
||||
@ -6427,9 +6407,6 @@ bool
|
||||
mjit::Compiler::jsop_setgname(PropertyName *name, bool popGuaranteed)
|
||||
{
|
||||
if (monitored(PC)) {
|
||||
if (script == outerScript)
|
||||
monitoredBytecodes.append(PC - script->code);
|
||||
|
||||
/* Global accesses are monitored only for a few names like __proto__. */
|
||||
jsop_setgname_slow(name);
|
||||
return true;
|
||||
@ -6444,7 +6421,7 @@ mjit::Compiler::jsop_setgname(PropertyName *name, bool popGuaranteed)
|
||||
* can't get a function later and cause the global object to become
|
||||
* branded, requiring a shape change if it changes again.
|
||||
*/
|
||||
types::HeapTypeSet *types = globalObj->getType(cx)->getProperty(cx, id, false);
|
||||
types::TypeSet *types = globalObj->getType(cx)->getProperty(cx, id, false);
|
||||
if (!types)
|
||||
return false;
|
||||
js::Shape *shape = globalObj->nativeLookup(cx, NameToId(name));
|
||||
@ -6800,8 +6777,8 @@ mjit::Compiler::jsop_regexp()
|
||||
&obj->global() != globalObj ||
|
||||
!cx->typeInferenceEnabled() ||
|
||||
analysis->localsAliasStack() ||
|
||||
types::HeapTypeSet::HasObjectFlags(cx, globalObj->getType(cx),
|
||||
types::OBJECT_FLAG_REGEXP_FLAGS_SET))
|
||||
types::TypeSet::HasObjectFlags(cx, globalObj->getType(cx),
|
||||
types::OBJECT_FLAG_REGEXP_FLAGS_SET))
|
||||
{
|
||||
prepareStubCall(Uses(0));
|
||||
masm.move(ImmPtr(obj), Registers::ArgReg1);
|
||||
@ -6831,7 +6808,7 @@ mjit::Compiler::jsop_regexp()
|
||||
jsbytecode *use = script->code + uses->offset;
|
||||
uint32_t which = uses->u.which;
|
||||
if (JSOp(*use) == JSOP_CALLPROP) {
|
||||
JSObject *callee = analysis->pushedTypes(use, 0)->getSingleton();
|
||||
JSObject *callee = analysis->pushedTypes(use, 0)->getSingleton(cx);
|
||||
if (callee && callee->isFunction()) {
|
||||
Native native = callee->toFunction()->maybeNative();
|
||||
if (native == js::regexp_exec || native == js::regexp_test) {
|
||||
@ -6841,7 +6818,7 @@ mjit::Compiler::jsop_regexp()
|
||||
}
|
||||
} else if (JSOp(*use) == JSOP_CALL && which == 0) {
|
||||
uint32_t argc = GET_ARGC(use);
|
||||
JSObject *callee = analysis->poppedTypes(use, argc + 1)->getSingleton();
|
||||
JSObject *callee = analysis->poppedTypes(use, argc + 1)->getSingleton(cx);
|
||||
if (callee && callee->isFunction() && argc >= 1 && which == argc - 1) {
|
||||
Native native = callee->toFunction()->maybeNative();
|
||||
if (native == js::str_match ||
|
||||
@ -6996,7 +6973,7 @@ mjit::Compiler::finishLoop(jsbytecode *head)
|
||||
* variables are coherent in such cases.
|
||||
*/
|
||||
for (uint32_t slot = ArgSlot(0); slot < TotalSlots(script); slot++) {
|
||||
if (a->varTypes[slot].getTypeTag() == JSVAL_TYPE_DOUBLE) {
|
||||
if (a->varTypes[slot].getTypeTag(cx) == JSVAL_TYPE_DOUBLE) {
|
||||
FrameEntry *fe = frame.getSlotEntry(slot);
|
||||
stubcc.masm.ensureInMemoryDouble(frame.addressOf(fe));
|
||||
}
|
||||
@ -7014,8 +6991,8 @@ mjit::Compiler::finishLoop(jsbytecode *head)
|
||||
analysis->trackSlot(newv->slot))
|
||||
{
|
||||
JS_ASSERT(newv->slot < TotalSlots(script));
|
||||
types::StackTypeSet *targetTypes = analysis->getValueTypes(newv->value);
|
||||
if (targetTypes->getKnownTypeTag() == JSVAL_TYPE_DOUBLE) {
|
||||
types::TypeSet *targetTypes = analysis->getValueTypes(newv->value);
|
||||
if (targetTypes->getKnownTypeTag(cx) == JSVAL_TYPE_DOUBLE) {
|
||||
FrameEntry *fe = frame.getSlotEntry(newv->slot);
|
||||
stubcc.masm.ensureInMemoryDouble(frame.addressOf(fe));
|
||||
}
|
||||
@ -7100,7 +7077,7 @@ mjit::Compiler::jumpAndRun(Jump j, jsbytecode *target, Jump *slow, bool *trampol
|
||||
if (cx->typeInferenceEnabled()) {
|
||||
RegisterAllocation *&alloc = analysis->getAllocation(target);
|
||||
if (!alloc) {
|
||||
alloc = cx->analysisLifoAlloc().new_<RegisterAllocation>(false);
|
||||
alloc = cx->typeLifoAlloc().new_<RegisterAllocation>(false);
|
||||
if (!alloc) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
@ -7204,9 +7181,9 @@ mjit::Compiler::constructThis()
|
||||
}
|
||||
|
||||
jsid id = NameToId(cx->runtime->atomState.classPrototypeAtom);
|
||||
types::HeapTypeSet *protoTypes = fun->getType(cx)->getProperty(cx, id, false);
|
||||
types::TypeSet *protoTypes = fun->getType(cx)->getProperty(cx, id, false);
|
||||
|
||||
JSObject *proto = protoTypes->getSingleton(cx);
|
||||
JSObject *proto = protoTypes->getSingleton(cx, true);
|
||||
if (!proto)
|
||||
break;
|
||||
|
||||
@ -7231,7 +7208,7 @@ mjit::Compiler::constructThis()
|
||||
* should this information change later.
|
||||
*/
|
||||
if (templateObject->type()->newScript)
|
||||
types::HeapTypeSet::WatchObjectStateChange(cx, templateObject->type());
|
||||
types::TypeSet::WatchObjectStateChange(cx, templateObject->type());
|
||||
|
||||
RegisterID result = frame.allocReg();
|
||||
Jump emptyFreeList = getNewObject(cx, result, templateObject);
|
||||
@ -7240,7 +7217,7 @@ mjit::Compiler::constructThis()
|
||||
stubcc.leave();
|
||||
|
||||
stubcc.masm.move(ImmPtr(proto), Registers::ArgReg1);
|
||||
OOL_STUBCALL(stubs::CreateThis, REJOIN_THIS_CREATED);
|
||||
OOL_STUBCALL(stubs::CreateThis, REJOIN_RESUME);
|
||||
|
||||
frame.setThis(result);
|
||||
|
||||
@ -7274,7 +7251,7 @@ mjit::Compiler::constructThis()
|
||||
prepareStubCall(Uses(0));
|
||||
if (protoReg != Registers::ArgReg1)
|
||||
masm.move(protoReg, Registers::ArgReg1);
|
||||
INLINE_STUBCALL(stubs::CreateThis, REJOIN_THIS_CREATED);
|
||||
INLINE_STUBCALL(stubs::CreateThis, REJOIN_RESUME);
|
||||
frame.freeReg(protoReg);
|
||||
return true;
|
||||
}
|
||||
@ -7399,7 +7376,7 @@ mjit::Compiler::jsop_in()
|
||||
FrameEntry *id = frame.peek(-2);
|
||||
|
||||
if (cx->typeInferenceEnabled() && id->isType(JSVAL_TYPE_INT32)) {
|
||||
types::StackTypeSet *types = analysis->poppedTypes(PC, 0);
|
||||
types::TypeSet *types = analysis->poppedTypes(PC, 0);
|
||||
|
||||
if (obj->mightBeType(JSVAL_TYPE_OBJECT) &&
|
||||
!types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
|
||||
@ -7501,11 +7478,11 @@ mjit::Compiler::fixDoubleTypes(jsbytecode *target)
|
||||
continue;
|
||||
}
|
||||
JS_ASSERT(newv->slot < TotalSlots(script));
|
||||
types::StackTypeSet *targetTypes = analysis->getValueTypes(newv->value);
|
||||
types::TypeSet *targetTypes = analysis->getValueTypes(newv->value);
|
||||
FrameEntry *fe = frame.getSlotEntry(newv->slot);
|
||||
VarType &vt = a->varTypes[newv->slot];
|
||||
JSValueType type = vt.getTypeTag();
|
||||
if (targetTypes->getKnownTypeTag() == JSVAL_TYPE_DOUBLE) {
|
||||
JSValueType type = vt.getTypeTag(cx);
|
||||
if (targetTypes->getKnownTypeTag(cx) == JSVAL_TYPE_DOUBLE) {
|
||||
if (type == JSVAL_TYPE_INT32) {
|
||||
fixedIntToDoubleEntries.append(newv->slot);
|
||||
frame.ensureDouble(fe);
|
||||
@ -7537,7 +7514,7 @@ mjit::Compiler::watchGlobalReallocation()
|
||||
JS_ASSERT(cx->typeInferenceEnabled());
|
||||
if (hasGlobalReallocation)
|
||||
return;
|
||||
types::HeapTypeSet::WatchObjectStateChange(cx, globalObj->getType(cx));
|
||||
types::TypeSet::WatchObjectStateChange(cx, globalObj->getType(cx));
|
||||
hasGlobalReallocation = true;
|
||||
}
|
||||
|
||||
@ -7554,7 +7531,7 @@ mjit::Compiler::updateVarType()
|
||||
* (see prepareInferenceTypes).
|
||||
*/
|
||||
|
||||
types::StackTypeSet *types = pushedTypeSet(0);
|
||||
types::TypeSet *types = pushedTypeSet(0);
|
||||
uint32_t slot = GetBytecodeSlot(script, PC);
|
||||
|
||||
if (analysis->trackSlot(slot)) {
|
||||
@ -7566,7 +7543,7 @@ mjit::Compiler::updateVarType()
|
||||
* maintained by the frame as a double. We might forget the exact
|
||||
* representation used by the next call to fixDoubleTypes, fix it now.
|
||||
*/
|
||||
if (vt.getTypeTag() == JSVAL_TYPE_DOUBLE)
|
||||
if (vt.getTypeTag(cx) == JSVAL_TYPE_DOUBLE)
|
||||
frame.ensureDouble(frame.getSlotEntry(slot));
|
||||
}
|
||||
}
|
||||
@ -7583,9 +7560,9 @@ mjit::Compiler::updateJoinVarTypes()
|
||||
while (newv->slot) {
|
||||
if (newv->slot < TotalSlots(script)) {
|
||||
VarType &vt = a->varTypes[newv->slot];
|
||||
JSValueType type = vt.getTypeTag();
|
||||
JSValueType type = vt.getTypeTag(cx);
|
||||
vt.setTypes(analysis->getValueTypes(newv->value));
|
||||
if (vt.getTypeTag() != type) {
|
||||
if (vt.getTypeTag(cx) != type) {
|
||||
/*
|
||||
* If the known type of a variable changes (even if the
|
||||
* variable itself has not been reassigned) then we can't
|
||||
@ -7616,7 +7593,7 @@ mjit::Compiler::restoreVarType()
|
||||
* of tracked variables match their inferred type (as tracked in varTypes),
|
||||
* but may have forgotten it due to a branch or syncAndForgetEverything.
|
||||
*/
|
||||
JSValueType type = a->varTypes[slot].getTypeTag();
|
||||
JSValueType type = a->varTypes[slot].getTypeTag(cx);
|
||||
if (type != JSVAL_TYPE_UNKNOWN &&
|
||||
(type != JSVAL_TYPE_DOUBLE || analysis->trackSlot(slot))) {
|
||||
FrameEntry *fe = frame.getSlotEntry(slot);
|
||||
@ -7631,8 +7608,8 @@ mjit::Compiler::knownPushedType(uint32_t pushed)
|
||||
{
|
||||
if (!cx->typeInferenceEnabled())
|
||||
return JSVAL_TYPE_UNKNOWN;
|
||||
types::StackTypeSet *types = analysis->pushedTypes(PC, pushed);
|
||||
return types->getKnownTypeTag();
|
||||
types::TypeSet *types = analysis->pushedTypes(PC, pushed);
|
||||
return types->getKnownTypeTag(cx);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -7650,7 +7627,7 @@ mjit::Compiler::mayPushUndefined(uint32_t pushed)
|
||||
return types->hasType(types::Type::UndefinedType());
|
||||
}
|
||||
|
||||
types::StackTypeSet *
|
||||
types::TypeSet *
|
||||
mjit::Compiler::pushedTypeSet(uint32_t pushed)
|
||||
{
|
||||
if (!cx->typeInferenceEnabled())
|
||||
@ -7687,8 +7664,8 @@ mjit::Compiler::pushedSingleton(unsigned pushed)
|
||||
if (!cx->typeInferenceEnabled())
|
||||
return NULL;
|
||||
|
||||
types::StackTypeSet *types = analysis->pushedTypes(PC, pushed);
|
||||
return types->getSingleton();
|
||||
types::TypeSet *types = analysis->pushedTypes(PC, pushed);
|
||||
return types->getSingleton(cx);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -7742,7 +7719,7 @@ mjit::Compiler::pushAddressMaybeBarrier(Address address, JSValueType type, bool
|
||||
}
|
||||
|
||||
MaybeJump
|
||||
mjit::Compiler::trySingleTypeTest(types::StackTypeSet *types, RegisterID typeReg)
|
||||
mjit::Compiler::trySingleTypeTest(types::TypeSet *types, RegisterID typeReg)
|
||||
{
|
||||
/*
|
||||
* If a type set we have a barrier on is monomorphic, generate a single
|
||||
@ -7752,7 +7729,7 @@ mjit::Compiler::trySingleTypeTest(types::StackTypeSet *types, RegisterID typeReg
|
||||
*/
|
||||
MaybeJump res;
|
||||
|
||||
switch (types->getKnownTypeTag()) {
|
||||
switch (types->getKnownTypeTag(cx)) {
|
||||
case JSVAL_TYPE_INT32:
|
||||
res.setJump(masm.testInt32(Assembler::NotEqual, typeReg));
|
||||
return res;
|
||||
@ -7775,7 +7752,7 @@ mjit::Compiler::trySingleTypeTest(types::StackTypeSet *types, RegisterID typeReg
|
||||
}
|
||||
|
||||
JSC::MacroAssembler::Jump
|
||||
mjit::Compiler::addTypeTest(types::StackTypeSet *types, RegisterID typeReg, RegisterID dataReg)
|
||||
mjit::Compiler::addTypeTest(types::TypeSet *types, RegisterID typeReg, RegisterID dataReg)
|
||||
{
|
||||
/*
|
||||
* :TODO: It would be good to merge this with GenerateTypeCheck, but the
|
||||
@ -7845,7 +7822,7 @@ mjit::Compiler::testBarrier(RegisterID typeReg, RegisterID dataReg,
|
||||
if (!cx->typeInferenceEnabled() || !(js_CodeSpec[*PC].format & JOF_TYPESET))
|
||||
return state;
|
||||
|
||||
types::StackTypeSet *types = analysis->bytecodeTypes(PC);
|
||||
types::TypeSet *types = analysis->bytecodeTypes(PC);
|
||||
if (types->unknown()) {
|
||||
/*
|
||||
* If the result of this opcode is already unknown, there is no way for
|
||||
@ -7864,8 +7841,7 @@ mjit::Compiler::testBarrier(RegisterID typeReg, RegisterID dataReg,
|
||||
return state;
|
||||
}
|
||||
|
||||
if (hasTypeBarriers(PC))
|
||||
typeBarrierBytecodes.append(PC - script->code);
|
||||
types->addFreeze(cx);
|
||||
|
||||
/* Cannot have type barriers when the result of the operation is already unknown. */
|
||||
JS_ASSERT(!types->unknown());
|
||||
|
@ -209,6 +209,7 @@ class Compiler : public BaseCompiler
|
||||
bool hasTypeCheck;
|
||||
bool typeMonitored;
|
||||
bool cached;
|
||||
types::TypeSet *rhsTypes;
|
||||
ValueRemat vr;
|
||||
union {
|
||||
ic::GetPropLabels getPropLabels_;
|
||||
@ -248,6 +249,7 @@ class Compiler : public BaseCompiler
|
||||
}
|
||||
ic.typeMonitored = typeMonitored;
|
||||
ic.cached = cached;
|
||||
ic.rhsTypes = rhsTypes;
|
||||
if (ic.isGet())
|
||||
ic.setLabels(getPropLabels());
|
||||
else if (ic.isSet())
|
||||
@ -319,19 +321,19 @@ class Compiler : public BaseCompiler
|
||||
*/
|
||||
class VarType {
|
||||
JSValueType type;
|
||||
types::StackTypeSet *types;
|
||||
types::TypeSet *types;
|
||||
|
||||
public:
|
||||
void setTypes(types::StackTypeSet *types) {
|
||||
void setTypes(types::TypeSet *types) {
|
||||
this->types = types;
|
||||
this->type = JSVAL_TYPE_MISSING;
|
||||
}
|
||||
|
||||
types::TypeSet *getTypes() { return types; }
|
||||
|
||||
JSValueType getTypeTag() {
|
||||
JSValueType getTypeTag(JSContext *cx) {
|
||||
if (type == JSVAL_TYPE_MISSING)
|
||||
type = types ? types->getKnownTypeTag() : JSVAL_TYPE_UNKNOWN;
|
||||
type = types ? types->getKnownTypeTag(cx) : JSVAL_TYPE_UNKNOWN;
|
||||
return type;
|
||||
}
|
||||
};
|
||||
@ -431,8 +433,6 @@ private:
|
||||
js::Vector<DoublePatch, 16, CompilerAllocPolicy> doubleList;
|
||||
js::Vector<JSObject*, 0, CompilerAllocPolicy> rootedTemplates;
|
||||
js::Vector<RegExpShared*, 0, CompilerAllocPolicy> rootedRegExps;
|
||||
js::Vector<uint32_t> monitoredBytecodes;
|
||||
js::Vector<uint32_t> typeBarrierBytecodes;
|
||||
js::Vector<uint32_t> fixedIntToDoubleEntries;
|
||||
js::Vector<uint32_t> fixedDoubleToAnyEntries;
|
||||
js::Vector<JumpTable, 16> jumpTables;
|
||||
@ -547,7 +547,7 @@ private:
|
||||
void restoreVarType();
|
||||
JSValueType knownPushedType(uint32_t pushed);
|
||||
bool mayPushUndefined(uint32_t pushed);
|
||||
types::StackTypeSet *pushedTypeSet(uint32_t which);
|
||||
types::TypeSet *pushedTypeSet(uint32_t which);
|
||||
bool monitored(jsbytecode *pc);
|
||||
bool hasTypeBarriers(jsbytecode *pc);
|
||||
bool testSingletonProperty(HandleObject obj, HandleId id);
|
||||
@ -562,8 +562,8 @@ private:
|
||||
RegisterID dataReg;
|
||||
};
|
||||
|
||||
MaybeJump trySingleTypeTest(types::StackTypeSet *types, RegisterID typeReg);
|
||||
Jump addTypeTest(types::StackTypeSet *types, RegisterID typeReg, RegisterID dataReg);
|
||||
MaybeJump trySingleTypeTest(types::TypeSet *types, RegisterID typeReg);
|
||||
Jump addTypeTest(types::TypeSet *types, RegisterID typeReg, RegisterID dataReg);
|
||||
BarrierState pushAddressMaybeBarrier(Address address, JSValueType type, bool reuseBase,
|
||||
bool testUndefined = false);
|
||||
BarrierState testBarrier(RegisterID typeReg, RegisterID dataReg,
|
||||
|
@ -615,7 +615,9 @@ mjit::Compiler::compileArrayConcat(types::TypeSet *thisTypes, types::TypeSet *ar
|
||||
* so check that type information already reflects possible side effects of
|
||||
* this call.
|
||||
*/
|
||||
types::HeapTypeSet *thisElemTypes = thisType->getProperty(cx, JSID_VOID, false);
|
||||
thisTypes->addFreeze(cx);
|
||||
argTypes->addFreeze(cx);
|
||||
types::TypeSet *thisElemTypes = thisType->getProperty(cx, JSID_VOID, false);
|
||||
if (!thisElemTypes)
|
||||
return Compile_Error;
|
||||
if (!pushedTypeSet(0)->hasType(types::Type::ObjectType(thisType)))
|
||||
@ -626,7 +628,7 @@ mjit::Compiler::compileArrayConcat(types::TypeSet *thisTypes, types::TypeSet *ar
|
||||
types::TypeObject *argType = argTypes->getTypeObject(i);
|
||||
if (!argType)
|
||||
continue;
|
||||
types::HeapTypeSet *elemTypes = argType->getProperty(cx, JSID_VOID, false);
|
||||
types::TypeSet *elemTypes = argType->getProperty(cx, JSID_VOID, false);
|
||||
if (!elemTypes)
|
||||
return Compile_Error;
|
||||
if (!elemTypes->knownSubset(cx, thisElemTypes))
|
||||
@ -873,7 +875,7 @@ mjit::Compiler::inlineNativeFunction(uint32_t argc, bool callingNew)
|
||||
|
||||
FrameEntry *origCallee = frame.peek(-((int)argc + 2));
|
||||
FrameEntry *thisValue = frame.peek(-((int)argc + 1));
|
||||
types::StackTypeSet *thisTypes = analysis->poppedTypes(PC, argc);
|
||||
types::TypeSet *thisTypes = analysis->poppedTypes(PC, argc);
|
||||
|
||||
if (!origCallee->isConstant() || !origCallee->isType(JSVAL_TYPE_OBJECT))
|
||||
return Compile_InlineAbort;
|
||||
@ -945,7 +947,7 @@ mjit::Compiler::inlineNativeFunction(uint32_t argc, bool callingNew)
|
||||
}
|
||||
} else if (argc == 1) {
|
||||
FrameEntry *arg = frame.peek(-1);
|
||||
types::StackTypeSet *argTypes = frame.extra(arg).types;
|
||||
types::TypeSet *argTypes = frame.extra(arg).types;
|
||||
if (!argTypes)
|
||||
return Compile_InlineAbort;
|
||||
JSValueType argType = arg->isTypeKnown() ? arg->getKnownType() : JSVAL_TYPE_UNKNOWN;
|
||||
|
@ -387,8 +387,8 @@ mjit::Compiler::jsop_equality_obj_obj(JSOp op, jsbytecode *target, JSOp fused)
|
||||
* special equality operator on either object, if that passes then
|
||||
* this is a pointer comparison.
|
||||
*/
|
||||
types::StackTypeSet *lhsTypes = analysis->poppedTypes(PC, 1);
|
||||
types::StackTypeSet *rhsTypes = analysis->poppedTypes(PC, 0);
|
||||
types::TypeSet *lhsTypes = analysis->poppedTypes(PC, 1);
|
||||
types::TypeSet *rhsTypes = analysis->poppedTypes(PC, 0);
|
||||
if (!lhsTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPECIAL_EQUALITY) &&
|
||||
!rhsTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPECIAL_EQUALITY)) {
|
||||
/* :TODO: Merge with jsop_relational_int? */
|
||||
@ -896,8 +896,8 @@ mjit::Compiler::jsop_localinc(JSOp op, uint32_t slot)
|
||||
{
|
||||
restoreVarType();
|
||||
|
||||
types::StackTypeSet *types = pushedTypeSet(0);
|
||||
JSValueType type = types ? types->getKnownTypeTag() : JSVAL_TYPE_UNKNOWN;
|
||||
types::TypeSet *types = pushedTypeSet(0);
|
||||
JSValueType type = types ? types->getKnownTypeTag(cx) : JSVAL_TYPE_UNKNOWN;
|
||||
|
||||
int amt = (op == JSOP_LOCALINC || op == JSOP_INCLOCAL) ? 1 : -1;
|
||||
|
||||
@ -959,8 +959,8 @@ mjit::Compiler::jsop_arginc(JSOp op, uint32_t slot)
|
||||
{
|
||||
restoreVarType();
|
||||
|
||||
types::StackTypeSet *types = pushedTypeSet(0);
|
||||
JSValueType type = types ? types->getKnownTypeTag() : JSVAL_TYPE_UNKNOWN;
|
||||
types::TypeSet *types = pushedTypeSet(0);
|
||||
JSValueType type = types ? types->getKnownTypeTag(cx) : JSVAL_TYPE_UNKNOWN;
|
||||
|
||||
int amt = (op == JSOP_ARGINC || op == JSOP_INCARG) ? 1 : -1;
|
||||
|
||||
@ -1169,7 +1169,7 @@ mjit::Compiler::jsop_setelem_dense()
|
||||
* because in that case the slot we're overwriting was previously
|
||||
* undefined.
|
||||
*/
|
||||
types::StackTypeSet *types = frame.extra(obj).types;
|
||||
types::TypeSet *types = frame.extra(obj).types;
|
||||
if (cx->compartment->compileBarriers() && (!types || types->propertyNeedsBarrier(cx, JSID_VOID))) {
|
||||
Label barrierStart = stubcc.masm.label();
|
||||
stubcc.linkExitDirect(masm.jump(), barrierStart);
|
||||
@ -1538,9 +1538,6 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed)
|
||||
FrameEntry *value = frame.peek(-1);
|
||||
|
||||
if (!IsCacheableSetElem(obj, id, value) || monitored(PC)) {
|
||||
if (monitored(PC) && script == outerScript)
|
||||
monitoredBytecodes.append(PC - script->code);
|
||||
|
||||
jsop_setelem_slow();
|
||||
return true;
|
||||
}
|
||||
@ -1548,7 +1545,7 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed)
|
||||
// If the object is definitely a dense array or a typed array we can generate
|
||||
// code directly without using an inline cache.
|
||||
if (cx->typeInferenceEnabled()) {
|
||||
types::StackTypeSet *types = analysis->poppedTypes(PC, 2);
|
||||
types::TypeSet *types = analysis->poppedTypes(PC, 2);
|
||||
|
||||
if (!types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
|
||||
!types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
|
||||
@ -1561,7 +1558,7 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed)
|
||||
if ((value->mightBeType(JSVAL_TYPE_INT32) || value->mightBeType(JSVAL_TYPE_DOUBLE)) &&
|
||||
!types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_TYPED_ARRAY)) {
|
||||
// Inline typed array path.
|
||||
int atype = types->getTypedArrayType();
|
||||
int atype = types->getTypedArrayType(cx);
|
||||
if (atype != TypedArray::TYPE_MAX) {
|
||||
jsop_setelem_typed(atype);
|
||||
return true;
|
||||
@ -2148,8 +2145,8 @@ mjit::Compiler::jsop_getelem()
|
||||
// If the object is definitely an arguments object, a dense array or a typed array
|
||||
// we can generate code directly without using an inline cache.
|
||||
if (cx->typeInferenceEnabled() && !id->isType(JSVAL_TYPE_STRING)) {
|
||||
types::StackTypeSet *types = analysis->poppedTypes(PC, 1);
|
||||
if (types->isMagicArguments() && !outerScript->analysis()->modifiesArguments()) {
|
||||
types::TypeSet *types = analysis->poppedTypes(PC, 1);
|
||||
if (types->isMagicArguments(cx) && !outerScript->analysis()->modifiesArguments()) {
|
||||
// Inline arguments path.
|
||||
jsop_getelem_args();
|
||||
return true;
|
||||
@ -2168,7 +2165,7 @@ mjit::Compiler::jsop_getelem()
|
||||
if (obj->mightBeType(JSVAL_TYPE_OBJECT) &&
|
||||
!types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_TYPED_ARRAY)) {
|
||||
// Inline typed array path.
|
||||
int atype = types->getTypedArrayType();
|
||||
int atype = types->getTypedArrayType(cx);
|
||||
if (atype != TypedArray::TYPE_MAX) {
|
||||
if (jsop_getelem_typed(atype))
|
||||
return true;
|
||||
@ -2689,9 +2686,6 @@ mjit::Compiler::jsop_initprop()
|
||||
RootedObject baseobj(cx, frame.extra(obj).initObject);
|
||||
|
||||
if (!baseobj || monitored(PC) || cx->compartment->compileBarriers()) {
|
||||
if (monitored(PC) && script == outerScript)
|
||||
monitoredBytecodes.append(PC - script->code);
|
||||
|
||||
prepareStubCall(Uses(2));
|
||||
masm.move(ImmPtr(name), Registers::ArgReg1);
|
||||
INLINE_STUBCALL(stubs::InitProp, REJOIN_FALLTHROUGH);
|
||||
|
@ -29,8 +29,7 @@ FrameState::~FrameState()
|
||||
{
|
||||
while (a) {
|
||||
ActiveFrame *parent = a->parent;
|
||||
if (a->script->hasAnalysis())
|
||||
a->script->analysis()->clearAllocations();
|
||||
a->script->analysis()->clearAllocations();
|
||||
cx->free_(a);
|
||||
a = parent;
|
||||
}
|
||||
@ -543,7 +542,7 @@ RegisterAllocation *
|
||||
FrameState::computeAllocation(jsbytecode *target)
|
||||
{
|
||||
JS_ASSERT(cx->typeInferenceEnabled());
|
||||
RegisterAllocation *alloc = cx->analysisLifoAlloc().new_<RegisterAllocation>(false);
|
||||
RegisterAllocation *alloc = cx->typeLifoAlloc().new_<RegisterAllocation>(false);
|
||||
if (!alloc) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
@ -593,8 +592,8 @@ FrameState::computeAllocation(jsbytecode *target)
|
||||
if (newv->value.kind() == SSAValue::PHI &&
|
||||
newv->value.phiOffset() == uint32_t(target - a->script->code) &&
|
||||
newv->slot == entrySlot(fe)) {
|
||||
types::StackTypeSet *types = a->analysis->getValueTypes(newv->value);
|
||||
if (types->getKnownTypeTag() != JSVAL_TYPE_DOUBLE)
|
||||
types::TypeSet *types = a->analysis->getValueTypes(newv->value);
|
||||
if (types->getKnownTypeTag(cx) != JSVAL_TYPE_DOUBLE)
|
||||
nonDoubleTarget = true;
|
||||
}
|
||||
newv++;
|
||||
@ -826,7 +825,7 @@ FrameState::discardForJoin(RegisterAllocation *&alloc, uint32_t stackDepth)
|
||||
* This shows up for loop entries which are not reachable from the
|
||||
* loop head, and for exception, switch target and trap safe points.
|
||||
*/
|
||||
alloc = cx->analysisLifoAlloc().new_<RegisterAllocation>(false);
|
||||
alloc = cx->typeLifoAlloc().new_<RegisterAllocation>(false);
|
||||
if (!alloc) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
|
@ -698,7 +698,7 @@ class FrameState
|
||||
struct StackEntryExtra {
|
||||
bool initArray;
|
||||
JSObject *initObject;
|
||||
types::StackTypeSet *types;
|
||||
types::TypeSet *types;
|
||||
JSAtom *name;
|
||||
void reset() { PodZero(this); }
|
||||
};
|
||||
|
@ -867,10 +867,7 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM
|
||||
if (!obj)
|
||||
return js_InternalThrow(f);
|
||||
fp->thisValue() = ObjectValue(*obj);
|
||||
/* FALLTHROUGH */
|
||||
}
|
||||
|
||||
case REJOIN_THIS_CREATED: {
|
||||
Probes::enterScript(f.cx, f.script(), f.script()->function(), fp);
|
||||
|
||||
if (script->debugMode) {
|
||||
@ -878,13 +875,9 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM
|
||||
switch (status) {
|
||||
case JSTRAP_CONTINUE:
|
||||
break;
|
||||
case JSTRAP_RETURN: {
|
||||
/* Advance to the JSOP_STOP at the end of the script. */
|
||||
f.regs.pc = script->code + script->length - 1;
|
||||
nextDepth = 0;
|
||||
JS_ASSERT(*f.regs.pc == JSOP_STOP);
|
||||
break;
|
||||
}
|
||||
case JSTRAP_RETURN:
|
||||
*f.returnAddressLocation() = f.cx->jaegerRuntime().forceReturnFromExternC();
|
||||
return NULL;
|
||||
case JSTRAP_THROW:
|
||||
case JSTRAP_ERROR:
|
||||
return js_InternalThrow(f);
|
||||
|
@ -126,7 +126,7 @@ LoopState::init(jsbytecode *head, Jump entry, jsbytecode *entryTarget)
|
||||
RegisterAllocation *&alloc = outerAnalysis->getAllocation(head);
|
||||
JS_ASSERT(!alloc);
|
||||
|
||||
alloc = cx->analysisLifoAlloc().new_<RegisterAllocation>(true);
|
||||
alloc = cx->typeLifoAlloc().new_<RegisterAllocation>(true);
|
||||
if (!alloc) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
@ -140,7 +140,7 @@ LoopState::init(jsbytecode *head, Jump entry, jsbytecode *entryTarget)
|
||||
* had indirect modification of their arguments.
|
||||
*/
|
||||
if (outerScript->function()) {
|
||||
if (HeapTypeSet::HasObjectFlags(cx, outerScript->function()->getType(cx), OBJECT_FLAG_UNINLINEABLE))
|
||||
if (TypeSet::HasObjectFlags(cx, outerScript->function()->getType(cx), OBJECT_FLAG_UNINLINEABLE))
|
||||
this->skipAnalysis = true;
|
||||
}
|
||||
|
||||
@ -778,10 +778,10 @@ LoopState::invariantLength(const CrossSSAValue &obj)
|
||||
int32_t objConstant;
|
||||
if (!getEntryValue(obj, &objSlot, &objConstant) || objSlot == UNASSIGNED || objConstant != 0)
|
||||
return NULL;
|
||||
StackTypeSet *objTypes = ssa->getValueTypes(obj);
|
||||
TypeSet *objTypes = ssa->getValueTypes(obj);
|
||||
|
||||
/* Check for 'length' on the lazy arguments for the current frame. */
|
||||
if (objTypes->isMagicArguments()) {
|
||||
if (objTypes->isMagicArguments(cx)) {
|
||||
JS_ASSERT(obj.frame == CrossScriptSSA::OUTER_FRAME);
|
||||
|
||||
for (unsigned i = 0; i < invariantEntries.length(); i++) {
|
||||
@ -824,6 +824,9 @@ LoopState::invariantLength(const CrossSSAValue &obj)
|
||||
|
||||
/* Hoist 'length' access on typed arrays. */
|
||||
if (!objTypes->hasObjectFlags(cx, OBJECT_FLAG_NON_TYPED_ARRAY)) {
|
||||
/* Recompile if object type changes. */
|
||||
objTypes->addFreeze(cx);
|
||||
|
||||
uint32_t which = frame.allocTemporary();
|
||||
if (which == UINT32_MAX)
|
||||
return NULL;
|
||||
@ -858,6 +861,7 @@ LoopState::invariantLength(const CrossSSAValue &obj)
|
||||
if (object && hasModifiedProperty(object, JSID_VOID))
|
||||
return NULL;
|
||||
}
|
||||
objTypes->addFreeze(cx);
|
||||
|
||||
uint32_t which = frame.allocTemporary();
|
||||
if (which == UINT32_MAX)
|
||||
@ -909,11 +913,12 @@ LoopState::invariantProperty(const CrossSSAValue &obj, jsid id)
|
||||
TypeObject *object = objTypes->getTypeObject(0);
|
||||
if (!object || object->unknownProperties() || hasModifiedProperty(object, id) || id != MakeTypeId(cx, id))
|
||||
return NULL;
|
||||
HeapTypeSet *propertyTypes = object->getProperty(cx, id, false);
|
||||
TypeSet *propertyTypes = object->getProperty(cx, id, false);
|
||||
if (!propertyTypes)
|
||||
return NULL;
|
||||
if (!propertyTypes->definiteProperty() || propertyTypes->isOwnProperty(cx, object, true))
|
||||
if (!propertyTypes->isDefiniteProperty() || propertyTypes->isOwnProperty(cx, object, true))
|
||||
return NULL;
|
||||
objTypes->addFreeze(cx);
|
||||
|
||||
uint32_t which = frame.allocTemporary();
|
||||
if (which == UINT32_MAX)
|
||||
@ -1173,8 +1178,8 @@ LoopState::ignoreIntegerOverflow(const CrossSSAValue &pushed)
|
||||
return false;
|
||||
}
|
||||
|
||||
StackTypeSet *lhsTypes = outerAnalysis->poppedTypes(use->offset, 1);
|
||||
if (lhsTypes->getKnownTypeTag() != JSVAL_TYPE_INT32)
|
||||
TypeSet *lhsTypes = outerAnalysis->poppedTypes(use->offset, 1);
|
||||
if (lhsTypes->getKnownTypeTag(cx) != JSVAL_TYPE_INT32)
|
||||
return false;
|
||||
|
||||
JaegerSpew(JSpew_Analysis, "Integer result is RHS in integer addition\n");
|
||||
@ -1566,8 +1571,8 @@ LoopState::analyzeLoopTest()
|
||||
SSAValue two = outerAnalysis->poppedValue(test.pushedOffset(), 0);
|
||||
|
||||
/* The test must be comparing known integers. */
|
||||
if (outerAnalysis->getValueTypes(one)->getKnownTypeTag() != JSVAL_TYPE_INT32 ||
|
||||
outerAnalysis->getValueTypes(two)->getKnownTypeTag() != JSVAL_TYPE_INT32) {
|
||||
if (outerAnalysis->getValueTypes(one)->getKnownTypeTag(cx) != JSVAL_TYPE_INT32 ||
|
||||
outerAnalysis->getValueTypes(two)->getKnownTypeTag(cx) != JSVAL_TYPE_INT32) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1670,11 +1675,11 @@ LoopState::definiteArrayAccess(const SSAValue &obj, const SSAValue &index)
|
||||
* other value by which the overflow could be observed.
|
||||
*/
|
||||
|
||||
StackTypeSet *objTypes = outerAnalysis->getValueTypes(obj);
|
||||
StackTypeSet *elemTypes = outerAnalysis->getValueTypes(index);
|
||||
TypeSet *objTypes = outerAnalysis->getValueTypes(obj);
|
||||
TypeSet *elemTypes = outerAnalysis->getValueTypes(index);
|
||||
|
||||
if (objTypes->getKnownTypeTag() != JSVAL_TYPE_OBJECT ||
|
||||
elemTypes->getKnownTypeTag() != JSVAL_TYPE_INT32) {
|
||||
if (objTypes->getKnownTypeTag(cx) != JSVAL_TYPE_OBJECT ||
|
||||
elemTypes->getKnownTypeTag(cx) != JSVAL_TYPE_INT32) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1796,18 +1801,19 @@ LoopState::analyzeLoopBody(unsigned frame)
|
||||
SSAValue objValue = analysis->poppedValue(pc, 2);
|
||||
SSAValue elemValue = analysis->poppedValue(pc, 1);
|
||||
|
||||
StackTypeSet *objTypes = analysis->getValueTypes(objValue);
|
||||
StackTypeSet *elemTypes = analysis->getValueTypes(elemValue);
|
||||
TypeSet *objTypes = analysis->getValueTypes(objValue);
|
||||
TypeSet *elemTypes = analysis->getValueTypes(elemValue);
|
||||
|
||||
/*
|
||||
* Mark the modset as unknown if the index might be non-integer,
|
||||
* we don't want to consider the SETELEM PIC here.
|
||||
*/
|
||||
if (objTypes->unknownObject() || elemTypes->getKnownTypeTag() != JSVAL_TYPE_INT32) {
|
||||
if (objTypes->unknownObject() || elemTypes->getKnownTypeTag(cx) != JSVAL_TYPE_INT32) {
|
||||
unknownModset = true;
|
||||
break;
|
||||
}
|
||||
|
||||
objTypes->addFreeze(cx);
|
||||
for (unsigned i = 0; i < objTypes->getObjectCount(); i++) {
|
||||
TypeObject *object = objTypes->getTypeObject(i);
|
||||
if (!object)
|
||||
@ -1842,6 +1848,7 @@ LoopState::analyzeLoopBody(unsigned frame)
|
||||
break;
|
||||
}
|
||||
|
||||
objTypes->addFreeze(cx);
|
||||
for (unsigned i = 0; i < objTypes->getObjectCount(); i++) {
|
||||
TypeObject *object = objTypes->getTypeObject(i);
|
||||
if (!object)
|
||||
@ -1909,7 +1916,7 @@ LoopState::analyzeLoopBody(unsigned frame)
|
||||
case JSOP_GE:
|
||||
case JSOP_STRICTEQ:
|
||||
case JSOP_STRICTNE: {
|
||||
JSValueType type = analysis->poppedTypes(pc, 1)->getKnownTypeTag();
|
||||
JSValueType type = analysis->poppedTypes(pc, 1)->getKnownTypeTag(cx);
|
||||
if (type != JSVAL_TYPE_INT32 && type != JSVAL_TYPE_DOUBLE)
|
||||
constrainedLoop = false;
|
||||
}
|
||||
@ -1918,7 +1925,7 @@ LoopState::analyzeLoopBody(unsigned frame)
|
||||
case JSOP_POS:
|
||||
case JSOP_NEG:
|
||||
case JSOP_BITNOT: {
|
||||
JSValueType type = analysis->poppedTypes(pc, 0)->getKnownTypeTag();
|
||||
JSValueType type = analysis->poppedTypes(pc, 0)->getKnownTypeTag(cx);
|
||||
if (type != JSVAL_TYPE_INT32 && type != JSVAL_TYPE_DOUBLE)
|
||||
constrainedLoop = false;
|
||||
break;
|
||||
|
@ -1122,22 +1122,10 @@ JITChunk::rootedRegExps() const
|
||||
return (RegExpShared **)&rootedTemplates()[nRootedTemplates];
|
||||
}
|
||||
|
||||
uint32_t *
|
||||
JITChunk::monitoredBytecodes() const
|
||||
{
|
||||
return (uint32_t *)&rootedRegExps()[nRootedRegExps];
|
||||
}
|
||||
|
||||
uint32_t *
|
||||
JITChunk::typeBarrierBytecodes() const
|
||||
{
|
||||
return (uint32_t *)&monitoredBytecodes()[nMonitoredBytecodes];
|
||||
}
|
||||
|
||||
char *
|
||||
JITChunk::commonSectionLimit() const
|
||||
{
|
||||
return (char *)&typeBarrierBytecodes()[nTypeBarrierBytecodes];
|
||||
return (char *)&rootedRegExps()[nRootedRegExps];
|
||||
}
|
||||
|
||||
#ifdef JS_MONOIC
|
||||
@ -1269,9 +1257,6 @@ JITScript::destroy(FreeOp *fop)
|
||||
for (unsigned i = 0; i < nchunks; i++)
|
||||
destroyChunk(fop, i);
|
||||
|
||||
if (liveness)
|
||||
fop->free_(liveness);
|
||||
|
||||
if (shimPool)
|
||||
shimPool->release();
|
||||
}
|
||||
@ -1399,8 +1384,6 @@ size_t
|
||||
mjit::JITScript::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf)
|
||||
{
|
||||
size_t n = mallocSizeOf(this);
|
||||
if (liveness)
|
||||
n += mallocSizeOf(liveness);
|
||||
for (unsigned i = 0; i < nchunks; i++) {
|
||||
const ChunkDescriptor &desc = chunkDescriptor(i);
|
||||
if (desc.chunk)
|
||||
@ -1419,8 +1402,6 @@ mjit::JITChunk::computedSizeOfIncludingThis()
|
||||
sizeof(CallSite) * nCallSites +
|
||||
sizeof(JSObject*) * nRootedTemplates +
|
||||
sizeof(RegExpShared*) * nRootedRegExps +
|
||||
sizeof(uint32_t) * nMonitoredBytecodes +
|
||||
sizeof(uint32_t) * nTypeBarrierBytecodes +
|
||||
#if defined JS_MONOIC
|
||||
sizeof(ic::GetGlobalNameIC) * nGetGlobalNames +
|
||||
sizeof(ic::SetGlobalNameIC) * nSetGlobalNames +
|
||||
|
@ -37,10 +37,6 @@ namespace mjit {
|
||||
struct JITScript;
|
||||
}
|
||||
|
||||
namespace analyze {
|
||||
struct ScriptLiveness;
|
||||
}
|
||||
|
||||
struct VMFrame
|
||||
{
|
||||
#if defined(JS_CPU_SPARC)
|
||||
@ -304,9 +300,6 @@ enum RejoinState {
|
||||
*/
|
||||
REJOIN_THIS_PROTOTYPE,
|
||||
|
||||
/* As above, after the 'this' object has been created. */
|
||||
REJOIN_THIS_CREATED,
|
||||
|
||||
/*
|
||||
* Type check on arguments failed during prologue, need stack check and
|
||||
* the rest of the JIT prologue before the script can execute.
|
||||
@ -656,8 +649,6 @@ struct JITChunk
|
||||
uint32_t nCallSites;
|
||||
uint32_t nRootedTemplates;
|
||||
uint32_t nRootedRegExps;
|
||||
uint32_t nMonitoredBytecodes;
|
||||
uint32_t nTypeBarrierBytecodes;
|
||||
#ifdef JS_MONOIC
|
||||
uint32_t nGetGlobalNames;
|
||||
uint32_t nSetGlobalNames;
|
||||
@ -686,15 +677,6 @@ struct JITChunk
|
||||
js::mjit::CallSite *callSites() const;
|
||||
JSObject **rootedTemplates() const;
|
||||
RegExpShared **rootedRegExps() const;
|
||||
|
||||
/*
|
||||
* Offsets of bytecodes which were monitored or had type barriers at the
|
||||
* point of compilation. Used to avoid unnecessary recompilation after
|
||||
* analysis purges.
|
||||
*/
|
||||
uint32_t *monitoredBytecodes() const;
|
||||
uint32_t *typeBarrierBytecodes() const;
|
||||
|
||||
#ifdef JS_MONOIC
|
||||
ic::GetGlobalNameIC *getGlobalNames() const;
|
||||
ic::SetGlobalNameIC *setGlobalNames() const;
|
||||
@ -804,12 +786,6 @@ struct JITScript
|
||||
*/
|
||||
JSC::ExecutablePool *shimPool;
|
||||
|
||||
/*
|
||||
* Optional liveness information attached to the JITScript if the analysis
|
||||
* information is purged while retaining JIT info.
|
||||
*/
|
||||
analyze::ScriptLiveness *liveness;
|
||||
|
||||
#ifdef JS_MONOIC
|
||||
/* Inline cache at function entry for checking this/argument types. */
|
||||
JSC::CodeLocationLabel argsCheckStub;
|
||||
|
@ -410,17 +410,7 @@ class SetPropCompiler : public PICStubCompiler
|
||||
types::TypeSet *types = type->getProperty(cx, types::MakeTypeId(cx, id), true);
|
||||
if (!types)
|
||||
return false;
|
||||
|
||||
jsbytecode *pc;
|
||||
JSScript *script = cx->stack.currentScript(&pc);
|
||||
|
||||
if (!script->ensureRanInference(cx) || monitor.recompiled())
|
||||
return false;
|
||||
|
||||
JS_ASSERT(*pc == JSOP_SETPROP || *pc == JSOP_SETNAME);
|
||||
|
||||
types::StackTypeSet *rhsTypes = script->analysis()->poppedTypes(pc, 0);
|
||||
rhsTypes->addSubset(cx, types);
|
||||
pic.rhsTypes->addSubset(cx, types);
|
||||
}
|
||||
|
||||
return !monitor.recompiled();
|
||||
|
@ -409,6 +409,9 @@ struct PICInfo : public BasePolyIC {
|
||||
// Offset from start of fast path to initial shape guard.
|
||||
uint32_t shapeGuard;
|
||||
|
||||
// Possible types of the RHS, for monitored SETPROP PICs.
|
||||
types::TypeSet *rhsTypes;
|
||||
|
||||
inline bool isSet() const {
|
||||
return kind == SET;
|
||||
}
|
||||
|
@ -725,8 +725,6 @@ pref("javascript.options.mem.gc_low_frequency_heap_growth", 150);
|
||||
pref("javascript.options.mem.gc_dynamic_heap_growth", true);
|
||||
pref("javascript.options.mem.gc_dynamic_mark_slice", true);
|
||||
|
||||
pref("javascript.options.mem.analysis_purge_mb", 100);
|
||||
|
||||
// advanced prefs
|
||||
pref("advanced.mailftp", false);
|
||||
pref("image.animation_mode", "normal");
|
||||
|
Loading…
Reference in New Issue
Block a user