mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-10 01:08:21 +00:00
Bug 915473 - Distinguish stack type sets from compiler-created temporary type sets, r=jandem.
This commit is contained in:
parent
705a73caba
commit
602e976657
@ -132,7 +132,6 @@ struct TypeInferenceSizes
|
||||
{
|
||||
size_t typeScripts;
|
||||
size_t typeResults;
|
||||
size_t analysisPool;
|
||||
size_t pendingArrays;
|
||||
size_t allocationSiteTables;
|
||||
size_t arrayTypeTables;
|
||||
@ -143,7 +142,6 @@ struct TypeInferenceSizes
|
||||
void add(TypeInferenceSizes &sizes) {
|
||||
this->typeScripts += sizes.typeScripts;
|
||||
this->typeResults += sizes.typeResults;
|
||||
this->analysisPool += sizes.analysisPool;
|
||||
this->pendingArrays += sizes.pendingArrays;
|
||||
this->allocationSiteTables += sizes.allocationSiteTables;
|
||||
this->arrayTypeTables += sizes.arrayTypeTables;
|
||||
|
@ -1626,8 +1626,8 @@ TryEliminateTypeBarrier(MTypeBarrier *barrier, bool *eliminated)
|
||||
{
|
||||
JS_ASSERT(!*eliminated);
|
||||
|
||||
const types::StackTypeSet *barrierTypes = barrier->resultTypeSet();
|
||||
const types::StackTypeSet *inputTypes = barrier->input()->resultTypeSet();
|
||||
const types::TemporaryTypeSet *barrierTypes = barrier->resultTypeSet();
|
||||
const types::TemporaryTypeSet *inputTypes = barrier->input()->resultTypeSet();
|
||||
|
||||
// Disregard the possible unbox added before the Typebarrier.
|
||||
if (barrier->input()->isUnbox() &&
|
||||
@ -2082,7 +2082,7 @@ jit::AnalyzeNewScriptProperties(JSContext *cx, JSFunction *fun,
|
||||
|
||||
Vector<jsid> accessedProperties(cx);
|
||||
|
||||
LifoAlloc alloc(JSCompartment::ANALYSIS_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
|
||||
LifoAlloc alloc(types::TypeZone::TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
|
||||
|
||||
TempAllocator temp(&alloc);
|
||||
IonContext ictx(cx, &temp);
|
||||
|
@ -147,7 +147,7 @@ IonBuilder::CFGState::TableSwitch(jsbytecode *exitpc, MTableSwitch *ins)
|
||||
}
|
||||
|
||||
JSFunction *
|
||||
IonBuilder::getSingleCallTarget(types::StackTypeSet *calleeTypes)
|
||||
IonBuilder::getSingleCallTarget(types::TemporaryTypeSet *calleeTypes)
|
||||
{
|
||||
if (!calleeTypes)
|
||||
return NULL;
|
||||
@ -160,7 +160,7 @@ IonBuilder::getSingleCallTarget(types::StackTypeSet *calleeTypes)
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::getPolyCallTargets(types::StackTypeSet *calleeTypes, bool constructing,
|
||||
IonBuilder::getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constructing,
|
||||
AutoObjectVector &targets, uint32_t maxTargets, bool *gotLambda)
|
||||
{
|
||||
JS_ASSERT(targets.length() == 0);
|
||||
@ -376,7 +376,7 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock *entry, jsbytecode *start, jsbytecod
|
||||
last = earlier;
|
||||
|
||||
if (js_CodeSpec[*last].format & JOF_TYPESET) {
|
||||
types::StackTypeSet *typeSet = types::TypeScript::BytecodeTypes(script(), last);
|
||||
types::TemporaryTypeSet *typeSet = bytecodeTypes(last);
|
||||
if (!typeSet->empty()) {
|
||||
MIRType type = MIRTypeFromValueType(typeSet->getKnownTypeTag());
|
||||
phi->addBackedgeType(type, typeSet);
|
||||
@ -744,14 +744,7 @@ IonBuilder::rewriteParameter(uint32_t slotIdx, MDefinition *param, int32_t argIn
|
||||
{
|
||||
JS_ASSERT(param->isParameter() || param->isGetArgumentsObjectArg());
|
||||
|
||||
// Find the original (not cloned) type set for the MParameter, as we
|
||||
// will be adding constraints to it.
|
||||
types::StackTypeSet *types;
|
||||
if (argIndex == MParameter::THIS_SLOT)
|
||||
types = types::TypeScript::ThisTypes(script());
|
||||
else
|
||||
types = types::TypeScript::ArgTypes(script(), argIndex);
|
||||
|
||||
types::TemporaryTypeSet *types = param->resultTypeSet();
|
||||
JSValueType definiteType = types->getKnownTypeTag();
|
||||
if (definiteType == JSVAL_TYPE_UNKNOWN)
|
||||
return;
|
||||
@ -900,7 +893,7 @@ IonBuilder::initArgumentsObject()
|
||||
|
||||
bool
|
||||
IonBuilder::addOsrValueTypeBarrier(uint32_t slot, MInstruction **def_,
|
||||
MIRType type, types::StackTypeSet *typeSet)
|
||||
MIRType type, types::TemporaryTypeSet *typeSet)
|
||||
{
|
||||
MInstruction *&def = *def_;
|
||||
MBasicBlock *osrBlock = def->block();
|
||||
@ -921,7 +914,7 @@ IonBuilder::addOsrValueTypeBarrier(uint32_t slot, MInstruction **def_,
|
||||
// No unbox instruction will be added below, so check the type by
|
||||
// adding a type barrier for a singleton type set.
|
||||
types::Type ntype = types::Type::PrimitiveType(ValueTypeFromMIRType(type));
|
||||
typeSet = GetIonContext()->temp->lifoAlloc()->new_<types::StackTypeSet>(ntype);
|
||||
typeSet = GetIonContext()->temp->lifoAlloc()->new_<types::TemporaryTypeSet>(ntype);
|
||||
if (!typeSet)
|
||||
return false;
|
||||
MInstruction *barrier = MTypeBarrier::New(def, typeSet);
|
||||
@ -1032,7 +1025,7 @@ IonBuilder::maybeAddOsrTypeBarriers()
|
||||
MPhi *preheaderPhi = preheader->getSlot(i)->toPhi();
|
||||
|
||||
MIRType type = headerPhi->type();
|
||||
types::StackTypeSet *typeSet = headerPhi->resultTypeSet();
|
||||
types::TemporaryTypeSet *typeSet = headerPhi->resultTypeSet();
|
||||
|
||||
if (!addOsrValueTypeBarrier(i, &def, type, typeSet))
|
||||
return false;
|
||||
@ -1403,8 +1396,7 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||
{
|
||||
types::TypeSet *argTypes = types::TypeScript::ArgTypes(script(), arg);
|
||||
|
||||
// During parallel compilation the parameter's type set
|
||||
// will be a clone of the actual argument type set.
|
||||
// Update both the original and cloned type set.
|
||||
argTypes->addType(cx, types::Type::UnknownType());
|
||||
op->resultTypeSet()->addType(cx, types::Type::UnknownType());
|
||||
}
|
||||
@ -4332,7 +4324,7 @@ IonBuilder::inlineCalls(CallInfo &callInfo, AutoObjectVector &targets,
|
||||
// During inlining the 'this' value is assigned a type set which is
|
||||
// specialized to the type objects which can generate that inlining target.
|
||||
// After inlining the original type set is restored.
|
||||
types::StackTypeSet *cacheObjectTypeSet =
|
||||
types::TemporaryTypeSet *cacheObjectTypeSet =
|
||||
maybeCache ? maybeCache->object()->resultTypeSet() : NULL;
|
||||
|
||||
// Inline each of the inlineable targets.
|
||||
@ -4378,7 +4370,7 @@ IonBuilder::inlineCalls(CallInfo &callInfo, AutoObjectVector &targets,
|
||||
|
||||
if (maybeCache) {
|
||||
JS_ASSERT(callInfo.thisArg() == maybeCache->object());
|
||||
types::StackTypeSet *targetThisTypes =
|
||||
types::TemporaryTypeSet *targetThisTypes =
|
||||
maybeCache->propTable()->buildTypeSetForFunction(original);
|
||||
if (!targetThisTypes)
|
||||
return false;
|
||||
@ -4704,7 +4696,7 @@ IonBuilder::jsop_funcall(uint32_t argc)
|
||||
int funcDepth = -((int)argc + 1);
|
||||
|
||||
// If |Function.prototype.call| may be overridden, don't optimize callsite.
|
||||
types::StackTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
|
||||
types::TemporaryTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
|
||||
RootedFunction native(cx, getSingleCallTarget(calleeTypes));
|
||||
if (!native || !native->isNative() || native->native() != &js_fun_call) {
|
||||
CallInfo callInfo(cx, false);
|
||||
@ -4715,7 +4707,7 @@ IonBuilder::jsop_funcall(uint32_t argc)
|
||||
current->peek(calleeDepth)->setFoldedUnchecked();
|
||||
|
||||
// Extract call target.
|
||||
types::StackTypeSet *funTypes = current->peek(funcDepth)->resultTypeSet();
|
||||
types::TemporaryTypeSet *funTypes = current->peek(funcDepth)->resultTypeSet();
|
||||
RootedFunction target(cx, getSingleCallTarget(funTypes));
|
||||
|
||||
// Unwrap the (JSFunction *) parameter.
|
||||
@ -4759,7 +4751,7 @@ IonBuilder::jsop_funapply(uint32_t argc)
|
||||
{
|
||||
int calleeDepth = -((int)argc + 2);
|
||||
|
||||
types::StackTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
|
||||
types::TemporaryTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
|
||||
RootedFunction native(cx, getSingleCallTarget(calleeTypes));
|
||||
if (argc != 2) {
|
||||
CallInfo callInfo(cx, false);
|
||||
@ -4811,7 +4803,7 @@ IonBuilder::jsop_funapplyarguments(uint32_t argc)
|
||||
int funcDepth = -((int)argc + 1);
|
||||
|
||||
// Extract call target.
|
||||
types::StackTypeSet *funTypes = current->peek(funcDepth)->resultTypeSet();
|
||||
types::TemporaryTypeSet *funTypes = current->peek(funcDepth)->resultTypeSet();
|
||||
RootedFunction target(cx, getSingleCallTarget(funTypes));
|
||||
|
||||
// When this script isn't inlined, use MApplyArgs,
|
||||
@ -4848,7 +4840,7 @@ IonBuilder::jsop_funapplyarguments(uint32_t argc)
|
||||
if (!resumeAfter(apply))
|
||||
return false;
|
||||
|
||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
return pushTypeBarrier(apply, types, true);
|
||||
}
|
||||
|
||||
@ -4922,7 +4914,7 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing)
|
||||
// Acquire known call target if existent.
|
||||
AutoObjectVector originals(cx);
|
||||
bool gotLambda = false;
|
||||
types::StackTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
|
||||
types::TemporaryTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
|
||||
if (calleeTypes) {
|
||||
if (!getPolyCallTargets(calleeTypes, constructing, originals, 4, &gotLambda))
|
||||
return false;
|
||||
@ -5066,7 +5058,7 @@ TestAreKnownDOMTypes(JSContext *cx, types::TypeSet *inTypes)
|
||||
|
||||
|
||||
static bool
|
||||
ArgumentTypesMatch(MDefinition *def, types::StackTypeSet *calleeTypes)
|
||||
ArgumentTypesMatch(MDefinition *def, types::TemporaryTypeSet *calleeTypes)
|
||||
{
|
||||
if (def->resultTypeSet()) {
|
||||
JS_ASSERT(def->type() == MIRType_Value || def->mightBeType(def->type()));
|
||||
@ -5082,8 +5074,8 @@ ArgumentTypesMatch(MDefinition *def, types::StackTypeSet *calleeTypes)
|
||||
return calleeTypes->mightBeType(ValueTypeFromMIRType(def->type()));
|
||||
}
|
||||
|
||||
static bool
|
||||
TestNeedsArgumentCheck(JSContext *cx, HandleFunction target, CallInfo &callInfo)
|
||||
bool
|
||||
IonBuilder::testNeedsArgumentCheck(JSContext *cx, HandleFunction target, CallInfo &callInfo)
|
||||
{
|
||||
// If we have a known target, check if the caller arg types are a subset of callee.
|
||||
// Since typeset accumulates and can't decrease that means we don't need to check
|
||||
@ -5095,15 +5087,15 @@ TestNeedsArgumentCheck(JSContext *cx, HandleFunction target, CallInfo &callInfo)
|
||||
if (!targetScript->hasAnalysis())
|
||||
return true;
|
||||
|
||||
if (!ArgumentTypesMatch(callInfo.thisArg(), types::TypeScript::ThisTypes(targetScript)))
|
||||
if (!ArgumentTypesMatch(callInfo.thisArg(), cloneTypeSet(types::TypeScript::ThisTypes(targetScript))))
|
||||
return true;
|
||||
uint32_t expected_args = Min<uint32_t>(callInfo.argc(), target->nargs);
|
||||
for (size_t i = 0; i < expected_args; i++) {
|
||||
if (!ArgumentTypesMatch(callInfo.getArg(i), types::TypeScript::ArgTypes(targetScript, i)))
|
||||
if (!ArgumentTypesMatch(callInfo.getArg(i), cloneTypeSet(types::TypeScript::ArgTypes(targetScript, i))))
|
||||
return true;
|
||||
}
|
||||
for (size_t i = callInfo.argc(); i < target->nargs; i++) {
|
||||
if (!types::TypeScript::ArgTypes(targetScript, i)->mightBeType(JSVAL_TYPE_UNDEFINED))
|
||||
if (!cloneTypeSet(types::TypeScript::ArgTypes(targetScript, i))->mightBeType(JSVAL_TYPE_UNDEFINED))
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -5196,7 +5188,7 @@ IonBuilder::makeCallHelper(HandleFunction target, CallInfo &callInfo, bool clone
|
||||
// We know we have a single call target. Check whether the "this" types
|
||||
// are DOM types and our function a DOM function, and if so flag the
|
||||
// MCall accordingly.
|
||||
types::StackTypeSet *thisTypes = thisArg->resultTypeSet();
|
||||
types::TemporaryTypeSet *thisTypes = thisArg->resultTypeSet();
|
||||
if (thisTypes &&
|
||||
TestAreKnownDOMTypes(cx, thisTypes) &&
|
||||
TestShouldDOMCall(cx, thisTypes, target, JSJitInfo::Method))
|
||||
@ -5205,7 +5197,7 @@ IonBuilder::makeCallHelper(HandleFunction target, CallInfo &callInfo, bool clone
|
||||
}
|
||||
}
|
||||
|
||||
if (target && !TestNeedsArgumentCheck(cx, target, callInfo))
|
||||
if (target && !testNeedsArgumentCheck(cx, target, callInfo))
|
||||
call->disableArgCheck();
|
||||
|
||||
call->initFunction(callInfo.fun());
|
||||
@ -5215,7 +5207,7 @@ IonBuilder::makeCallHelper(HandleFunction target, CallInfo &callInfo, bool clone
|
||||
}
|
||||
|
||||
static bool
|
||||
DOMCallNeedsBarrier(const JSJitInfo* jitinfo, types::StackTypeSet *types)
|
||||
DOMCallNeedsBarrier(const JSJitInfo* jitinfo, types::TemporaryTypeSet *types)
|
||||
{
|
||||
// If the return type of our DOM native is in "types" already, we don't
|
||||
// actually need a barrier.
|
||||
@ -5247,7 +5239,7 @@ IonBuilder::makeCall(HandleFunction target, CallInfo &callInfo, bool cloneAtCall
|
||||
if (!resumeAfter(call))
|
||||
return false;
|
||||
|
||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
|
||||
bool barrier = true;
|
||||
if (call->isDOMFunction()) {
|
||||
@ -5263,7 +5255,7 @@ bool
|
||||
IonBuilder::jsop_eval(uint32_t argc)
|
||||
{
|
||||
int calleeDepth = -((int)argc + 2);
|
||||
types::StackTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
|
||||
types::TemporaryTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
|
||||
|
||||
// Emit a normal call if the eval has never executed. This keeps us from
|
||||
// disabling compilation for the script when testing with --ion-eager.
|
||||
@ -5281,7 +5273,7 @@ IonBuilder::jsop_eval(uint32_t argc)
|
||||
if (!info().fun())
|
||||
return abort("Direct eval in global code");
|
||||
|
||||
types::StackTypeSet *thisTypes = types::TypeScript::ThisTypes(script());
|
||||
types::TemporaryTypeSet *thisTypes = cloneTypeSet(types::TypeScript::ThisTypes(script()));
|
||||
|
||||
// The 'this' value for the outer and eval scripts must be the
|
||||
// same. This is not guaranteed if a primitive string/number/etc.
|
||||
@ -5342,7 +5334,7 @@ IonBuilder::jsop_eval(uint32_t argc)
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
return resumeAfter(ins) && pushTypeBarrier(ins, types, true);
|
||||
}
|
||||
|
||||
@ -5399,9 +5391,15 @@ IonBuilder::jsop_newarray(uint32_t count)
|
||||
if (!templateObject)
|
||||
return false;
|
||||
|
||||
types::StackTypeSet::DoubleConversion conversion =
|
||||
types::TypeScript::BytecodeTypes(script(), pc)->convertDoubleElements(cx);
|
||||
if (conversion == types::StackTypeSet::AlwaysConvertToDoubles)
|
||||
if (templateObject->type()->unknownProperties()) {
|
||||
// We will get confused in jsop_initelem_array if we can't find the
|
||||
// type object being initialized.
|
||||
return abort("New array has unknown properties");
|
||||
}
|
||||
|
||||
types::TemporaryTypeSet::DoubleConversion conversion =
|
||||
bytecodeTypes(pc)->convertDoubleElements(cx);
|
||||
if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
|
||||
templateObject->setShouldConvertDoubleElements();
|
||||
|
||||
MNewArray *ins = new MNewArray(count, templateObject, MNewArray::NewArray_Allocating);
|
||||
@ -5883,8 +5881,8 @@ IonBuilder::newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc, bool
|
||||
? MIRType_Double
|
||||
: MIRTypeFromValueType(existingValue.extractNonDoubleType());
|
||||
types::Type ntype = types::GetValueType(existingValue);
|
||||
types::StackTypeSet *typeSet =
|
||||
GetIonContext()->temp->lifoAlloc()->new_<types::StackTypeSet>(ntype);
|
||||
types::TemporaryTypeSet *typeSet =
|
||||
GetIonContext()->temp->lifoAlloc()->new_<types::TemporaryTypeSet>(ntype);
|
||||
if (!typeSet)
|
||||
return NULL;
|
||||
phi->addBackedgeType(type, typeSet);
|
||||
@ -6034,7 +6032,7 @@ TestSingletonPropertyTypes(JSContext *cx, MDefinition *obj, JSObject *singleton,
|
||||
*testObject = false;
|
||||
*testString = false;
|
||||
|
||||
types::StackTypeSet *types = obj->resultTypeSet();
|
||||
types::TemporaryTypeSet *types = obj->resultTypeSet();
|
||||
|
||||
if (!types && obj->type() != MIRType_String)
|
||||
return true;
|
||||
@ -6145,7 +6143,7 @@ TestSingletonPropertyTypes(JSContext *cx, MDefinition *obj, JSObject *singleton,
|
||||
// instruction replaces the top of the stack.
|
||||
// (5) Lastly, a type barrier instruction replaces the top of the stack.
|
||||
bool
|
||||
IonBuilder::pushTypeBarrier(MInstruction *ins, types::StackTypeSet *observed, bool needsBarrier)
|
||||
IonBuilder::pushTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *observed, bool needsBarrier)
|
||||
{
|
||||
// Barriers are never needed for instructions whose result will not be used.
|
||||
if (BytecodeIsPopped(pc))
|
||||
@ -6184,9 +6182,9 @@ IonBuilder::pushTypeBarrier(MInstruction *ins, types::StackTypeSet *observed, bo
|
||||
current->pop();
|
||||
current->add(replace);
|
||||
current->push(replace);
|
||||
replace->setResultTypeSet(cloneTypeSet(observed));
|
||||
replace->setResultTypeSet(observed);
|
||||
} else {
|
||||
ins->setResultTypeSet(cloneTypeSet(observed));
|
||||
ins->setResultTypeSet(observed);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -6196,7 +6194,7 @@ IonBuilder::pushTypeBarrier(MInstruction *ins, types::StackTypeSet *observed, bo
|
||||
|
||||
current->pop();
|
||||
|
||||
MInstruction *barrier = MTypeBarrier::New(ins, cloneTypeSet(observed));
|
||||
MInstruction *barrier = MTypeBarrier::New(ins, observed);
|
||||
current->add(barrier);
|
||||
|
||||
if (barrier->type() == MIRType_Undefined)
|
||||
@ -6251,13 +6249,14 @@ IonBuilder::getStaticName(HandleObject staticObject, HandlePropertyName name, bo
|
||||
return true;
|
||||
}
|
||||
|
||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
bool barrier;
|
||||
if (!PropertyReadNeedsTypeBarrier(cx, staticType, name, types, /* updateObserved = */ true,
|
||||
if (!PropertyReadNeedsTypeBarrier(cx, staticType, name, baseTypes, /* updateObserved = */ true,
|
||||
&barrier))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
|
||||
|
||||
// If the property is permanent, a shape guard isn't necessary.
|
||||
|
||||
@ -6426,14 +6425,14 @@ IonBuilder::jsop_getname(HandlePropertyName name)
|
||||
if (!resumeAfter(ins))
|
||||
return false;
|
||||
|
||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
return pushTypeBarrier(ins, types, true);
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_intrinsic(HandlePropertyName name)
|
||||
{
|
||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
JSValueType type = types->getKnownTypeTag();
|
||||
|
||||
// If we haven't executed this opcode yet, we need to get the intrinsic
|
||||
@ -6479,7 +6478,7 @@ IonBuilder::jsop_bindname(PropertyName *name)
|
||||
}
|
||||
|
||||
static JSValueType
|
||||
GetElemKnownType(bool needsHoleCheck, types::StackTypeSet *types)
|
||||
GetElemKnownType(bool needsHoleCheck, types::TemporaryTypeSet *types)
|
||||
{
|
||||
JSValueType knownType = types->getKnownTypeTag();
|
||||
|
||||
@ -6540,7 +6539,7 @@ IonBuilder::jsop_getelem()
|
||||
if (!resumeAfter(ins))
|
||||
return false;
|
||||
|
||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
return pushTypeBarrier(ins, types, true);
|
||||
}
|
||||
|
||||
@ -6712,7 +6711,7 @@ IonBuilder::getElemTryArguments(bool *emitted, MDefinition *obj, MDefinition *in
|
||||
current->add(load);
|
||||
current->push(load);
|
||||
|
||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
if (!pushTypeBarrier(load, types, true))
|
||||
return false;
|
||||
|
||||
@ -6781,10 +6780,11 @@ IonBuilder::getElemTryCache(bool *emitted, MDefinition *obj, MDefinition *index)
|
||||
|
||||
// Emit GetElementCache.
|
||||
|
||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
bool barrier;
|
||||
if (!PropertyReadNeedsTypeBarrier(cx, obj, NULL, types, &barrier))
|
||||
if (!PropertyReadNeedsTypeBarrier(cx, obj, NULL, baseTypes, &barrier))
|
||||
return false;
|
||||
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
|
||||
|
||||
// Always add a barrier if the index might be a string, so that the cache
|
||||
// can attach stubs for particular properties.
|
||||
@ -6822,19 +6822,20 @@ IonBuilder::getElemTryCache(bool *emitted, MDefinition *obj, MDefinition *index)
|
||||
bool
|
||||
IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
|
||||
{
|
||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
|
||||
if (JSOp(*pc) == JSOP_CALLELEM && !index->mightBeType(MIRType_String) && types->noConstraints()) {
|
||||
if (JSOp(*pc) == JSOP_CALLELEM && !index->mightBeType(MIRType_String) && baseTypes->noConstraints()) {
|
||||
// Indexed call on an element of an array. Populate the observed types
|
||||
// with any objects that could be in the array, to avoid extraneous
|
||||
// type barriers.
|
||||
if (!AddObjectsForPropertyRead(cx, obj, NULL, types))
|
||||
if (!AddObjectsForPropertyRead(cx, obj, NULL, baseTypes))
|
||||
return false;
|
||||
}
|
||||
|
||||
bool barrier;
|
||||
if (!PropertyReadNeedsTypeBarrier(cx, obj, NULL, types, &barrier))
|
||||
if (!PropertyReadNeedsTypeBarrier(cx, obj, NULL, baseTypes, &barrier))
|
||||
return false;
|
||||
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
|
||||
|
||||
bool needsHoleCheck = !ElementAccessIsPacked(cx, obj);
|
||||
|
||||
@ -6870,7 +6871,7 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
|
||||
// NB: We disable this optimization in parallel execution mode
|
||||
// because it is inherently not threadsafe (how do you convert the
|
||||
// array atomically when there might be concurrent readers)?
|
||||
types::StackTypeSet *objTypes = obj->resultTypeSet();
|
||||
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
|
||||
ExecutionMode executionMode = info().executionMode();
|
||||
bool loadDouble =
|
||||
executionMode == SequentialExecution &&
|
||||
@ -6880,7 +6881,7 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
|
||||
!needsHoleCheck &&
|
||||
knownType == JSVAL_TYPE_DOUBLE &&
|
||||
objTypes &&
|
||||
objTypes->convertDoubleElements(cx) == types::StackTypeSet::AlwaysConvertToDoubles;
|
||||
objTypes->convertDoubleElements(cx) == types::TemporaryTypeSet::AlwaysConvertToDoubles;
|
||||
if (loadDouble)
|
||||
elements = addConvertElementsToDoubles(elements);
|
||||
|
||||
@ -6987,7 +6988,7 @@ bool
|
||||
IonBuilder::jsop_getelem_typed(MDefinition *obj, MDefinition *index,
|
||||
ScalarTypeRepresentation::Type arrayType)
|
||||
{
|
||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
|
||||
bool maybeUndefined = types->hasType(types::Type::UndefinedType());
|
||||
|
||||
@ -7213,11 +7214,11 @@ IonBuilder::setElemTryDense(bool *emitted, MDefinition *object,
|
||||
if (!object->resultTypeSet())
|
||||
return true;
|
||||
|
||||
types::StackTypeSet::DoubleConversion conversion =
|
||||
types::TemporaryTypeSet::DoubleConversion conversion =
|
||||
object->resultTypeSet()->convertDoubleElements(cx);
|
||||
|
||||
// If AmbiguousDoubleConversion, only handle int32 values for now.
|
||||
if (conversion == types::StackTypeSet::AmbiguousDoubleConversion &&
|
||||
if (conversion == types::TemporaryTypeSet::AmbiguousDoubleConversion &&
|
||||
value->type() != MIRType_Int32)
|
||||
{
|
||||
return true;
|
||||
@ -7291,7 +7292,7 @@ IonBuilder::setElemTryCache(bool *emitted, MDefinition *object,
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion,
|
||||
IonBuilder::jsop_setelem_dense(types::TemporaryTypeSet::DoubleConversion conversion,
|
||||
SetElemSafety safety,
|
||||
MDefinition *obj, MDefinition *id, MDefinition *value)
|
||||
{
|
||||
@ -7320,15 +7321,15 @@ IonBuilder::jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion,
|
||||
// Ensure the value is a double, if double conversion might be needed.
|
||||
MDefinition *newValue = value;
|
||||
switch (conversion) {
|
||||
case types::StackTypeSet::AlwaysConvertToDoubles:
|
||||
case types::StackTypeSet::MaybeConvertToDoubles: {
|
||||
case types::TemporaryTypeSet::AlwaysConvertToDoubles:
|
||||
case types::TemporaryTypeSet::MaybeConvertToDoubles: {
|
||||
MInstruction *valueDouble = MToDouble::New(value);
|
||||
current->add(valueDouble);
|
||||
newValue = valueDouble;
|
||||
break;
|
||||
}
|
||||
|
||||
case types::StackTypeSet::AmbiguousDoubleConversion: {
|
||||
case types::TemporaryTypeSet::AmbiguousDoubleConversion: {
|
||||
JS_ASSERT(value->type() == MIRType_Int32);
|
||||
MInstruction *maybeDouble = MMaybeToDoubleElement::New(elements, value);
|
||||
current->add(maybeDouble);
|
||||
@ -7336,7 +7337,7 @@ IonBuilder::jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion,
|
||||
break;
|
||||
}
|
||||
|
||||
case types::StackTypeSet::DontConvertToDoubles:
|
||||
case types::TemporaryTypeSet::DontConvertToDoubles:
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -7479,7 +7480,7 @@ IonBuilder::jsop_length()
|
||||
bool
|
||||
IonBuilder::jsop_length_fastPath()
|
||||
{
|
||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
|
||||
if (types->getKnownTypeTag() != JSVAL_TYPE_INT32)
|
||||
return false;
|
||||
@ -7497,7 +7498,7 @@ IonBuilder::jsop_length_fastPath()
|
||||
}
|
||||
|
||||
if (obj->mightBeType(MIRType_Object)) {
|
||||
types::StackTypeSet *objTypes = obj->resultTypeSet();
|
||||
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
|
||||
|
||||
if (objTypes &&
|
||||
objTypes->getKnownClass() == &ArrayObject::class_ &&
|
||||
@ -7625,7 +7626,7 @@ IonBuilder::jsop_rest()
|
||||
}
|
||||
|
||||
inline types::HeapTypeSet *
|
||||
GetDefiniteSlot(JSContext *cx, types::StackTypeSet *types, JSAtom *atom)
|
||||
GetDefiniteSlot(JSContext *cx, types::TemporaryTypeSet *types, JSAtom *atom)
|
||||
{
|
||||
if (!types || types->unknownObject() || types->getObjectCount() != 1)
|
||||
return NULL;
|
||||
@ -7740,7 +7741,7 @@ TestCommonAccessorProtoChain(JSContext *cx, HandleId id, bool isGetter, JSObject
|
||||
}
|
||||
|
||||
inline bool
|
||||
SearchCommonPropFunc(JSContext *cx, types::StackTypeSet *types, HandleId id, bool isGetter,
|
||||
SearchCommonPropFunc(JSContext *cx, types::TemporaryTypeSet *types, HandleId id, bool isGetter,
|
||||
JSObject *&found, JSObject *&foundProto, bool &cont)
|
||||
{
|
||||
cont = false;
|
||||
@ -7834,7 +7835,7 @@ SearchCommonPropFunc(JSContext *cx, types::StackTypeSet *types, HandleId id, boo
|
||||
}
|
||||
|
||||
inline bool
|
||||
FreezePropTypeSets(JSContext *cx, types::StackTypeSet *types, JSObject *foundProto, HandleId id)
|
||||
FreezePropTypeSets(JSContext *cx, types::TemporaryTypeSet *types, JSObject *foundProto, HandleId id)
|
||||
{
|
||||
types::TypeObject *curType;
|
||||
for (unsigned i = 0; i < types->getObjectCount(); i++) {
|
||||
@ -7879,7 +7880,7 @@ FreezePropTypeSets(JSContext *cx, types::StackTypeSet *types, JSObject *foundPro
|
||||
}
|
||||
|
||||
inline bool
|
||||
IonBuilder::TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types, HandleId id,
|
||||
IonBuilder::TestCommonPropFunc(JSContext *cx, types::TemporaryTypeSet *types, HandleId id,
|
||||
JSFunction **funcp, bool isGetter, bool *isDOM,
|
||||
MDefinition **guardOut)
|
||||
{
|
||||
@ -7934,7 +7935,7 @@ IonBuilder::TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types, Handle
|
||||
|
||||
bool
|
||||
IonBuilder::annotateGetPropertyCache(JSContext *cx, MDefinition *obj, MGetPropertyCache *getPropCache,
|
||||
types::StackTypeSet *objTypes, types::StackTypeSet *pushedTypes)
|
||||
types::TemporaryTypeSet *objTypes, types::TemporaryTypeSet *pushedTypes)
|
||||
{
|
||||
RootedId id(cx, NameToId(getPropCache->name()));
|
||||
if (id != types::IdToTypeId(id))
|
||||
@ -8047,7 +8048,7 @@ IonBuilder::invalidatedIdempotentCache()
|
||||
|
||||
bool
|
||||
IonBuilder::loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType,
|
||||
bool barrier, types::StackTypeSet *types)
|
||||
bool barrier, types::TemporaryTypeSet *types)
|
||||
{
|
||||
JS_ASSERT(shape->hasDefaultGetter());
|
||||
JS_ASSERT(shape->hasSlot());
|
||||
@ -8109,15 +8110,15 @@ IonBuilder::jsop_getprop(HandlePropertyName name)
|
||||
|
||||
bool emitted = false;
|
||||
|
||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
|
||||
// Try to optimize arguments.length.
|
||||
if (!getPropTryArgumentsLength(&emitted) || emitted)
|
||||
return emitted;
|
||||
|
||||
types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
bool barrier;
|
||||
if (!PropertyReadNeedsTypeBarrier(cx, current->peek(-1), name, types, &barrier))
|
||||
if (!PropertyReadNeedsTypeBarrier(cx, current->peek(-1), name, baseTypes, &barrier))
|
||||
return false;
|
||||
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
|
||||
|
||||
// Try to hardcode known constants.
|
||||
if (!getPropTryConstant(&emitted, id, types) || emitted)
|
||||
@ -8178,7 +8179,7 @@ IonBuilder::getPropTryArgumentsLength(bool *emitted)
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::getPropTryConstant(bool *emitted, HandleId id, types::StackTypeSet *types)
|
||||
IonBuilder::getPropTryConstant(bool *emitted, HandleId id, types::TemporaryTypeSet *types)
|
||||
{
|
||||
JS_ASSERT(*emitted == false);
|
||||
JSObject *singleton = types ? types->getSingleton() : NULL;
|
||||
@ -8217,7 +8218,7 @@ IonBuilder::getPropTryConstant(bool *emitted, HandleId id, types::StackTypeSet *
|
||||
|
||||
bool
|
||||
IonBuilder::getPropTryDefiniteSlot(bool *emitted, HandlePropertyName name,
|
||||
bool barrier, types::StackTypeSet *types)
|
||||
bool barrier, types::TemporaryTypeSet *types)
|
||||
{
|
||||
JS_ASSERT(*emitted == false);
|
||||
types::TypeSet *propTypes = GetDefiniteSlot(cx, current->peek(-1)->resultTypeSet(), name);
|
||||
@ -8248,14 +8249,14 @@ IonBuilder::getPropTryDefiniteSlot(bool *emitted, HandlePropertyName name,
|
||||
|
||||
bool
|
||||
IonBuilder::getPropTryCommonGetter(bool *emitted, HandleId id,
|
||||
bool barrier, types::StackTypeSet *types)
|
||||
bool barrier, types::TemporaryTypeSet *types)
|
||||
{
|
||||
JS_ASSERT(*emitted == false);
|
||||
JSFunction *commonGetter;
|
||||
bool isDOM;
|
||||
MDefinition *guard;
|
||||
|
||||
types::StackTypeSet *objTypes = current->peek(-1)->resultTypeSet();
|
||||
types::TemporaryTypeSet *objTypes = current->peek(-1)->resultTypeSet();
|
||||
|
||||
if (!TestCommonPropFunc(cx, objTypes, id, &commonGetter, true, &isDOM, &guard))
|
||||
return false;
|
||||
@ -8330,7 +8331,7 @@ CanInlinePropertyOpShapes(const Vector<Shape *> &shapes)
|
||||
|
||||
bool
|
||||
IonBuilder::getPropTryInlineAccess(bool *emitted, HandlePropertyName name, HandleId id,
|
||||
bool barrier, types::StackTypeSet *types)
|
||||
bool barrier, types::TemporaryTypeSet *types)
|
||||
{
|
||||
JS_ASSERT(*emitted == false);
|
||||
if (current->peek(-1)->type() != MIRType_Object)
|
||||
@ -8391,7 +8392,7 @@ IonBuilder::getPropTryInlineAccess(bool *emitted, HandlePropertyName name, Handl
|
||||
|
||||
bool
|
||||
IonBuilder::getPropTryCache(bool *emitted, HandlePropertyName name, HandleId id,
|
||||
bool barrier, types::StackTypeSet *types)
|
||||
bool barrier, types::TemporaryTypeSet *types)
|
||||
{
|
||||
JS_ASSERT(*emitted == false);
|
||||
bool accessGetter =
|
||||
@ -8403,7 +8404,7 @@ IonBuilder::getPropTryCache(bool *emitted, HandlePropertyName name, HandleId id,
|
||||
// The input value must either be an object, or we should have strong suspicions
|
||||
// that it can be safely unboxed to an object.
|
||||
if (obj->type() != MIRType_Object) {
|
||||
types::StackTypeSet *types = obj->resultTypeSet();
|
||||
types::TemporaryTypeSet *types = obj->resultTypeSet();
|
||||
if (!types || !types->objectOrSentinel())
|
||||
return true;
|
||||
}
|
||||
@ -8464,7 +8465,7 @@ IonBuilder::getPropTryCache(bool *emitted, HandlePropertyName name, HandleId id,
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::needsToMonitorMissingProperties(types::StackTypeSet *types)
|
||||
IonBuilder::needsToMonitorMissingProperties(types::TemporaryTypeSet *types)
|
||||
{
|
||||
// GetPropertyParIC and GetElementParIC cannot safely call
|
||||
// TypeScript::Monitor to ensure that the observed type set contains
|
||||
@ -8500,7 +8501,7 @@ IonBuilder::jsop_setprop(HandlePropertyName name)
|
||||
if (!setPropTryCommonSetter(&emitted, obj, name, id, value) || emitted)
|
||||
return emitted;
|
||||
|
||||
types::StackTypeSet *objTypes = obj->resultTypeSet();
|
||||
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
|
||||
bool barrier;
|
||||
if (!PropertyWriteNeedsTypeBarrier(cx, current, &obj, name, &value,
|
||||
/* canModify = */ true, &barrier))
|
||||
@ -8537,7 +8538,7 @@ IonBuilder::setPropTryCommonSetter(bool *emitted, MDefinition *obj,
|
||||
JSFunction *commonSetter;
|
||||
bool isDOM;
|
||||
|
||||
types::StackTypeSet *objTypes = obj->resultTypeSet();
|
||||
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
|
||||
if (!TestCommonPropFunc(cx, objTypes, id, &commonSetter, false, &isDOM, NULL))
|
||||
return false;
|
||||
|
||||
@ -8623,7 +8624,7 @@ IonBuilder::setPropTryCommonDOMSetter(bool *emitted, MDefinition *obj,
|
||||
if (!isDOM)
|
||||
return true;
|
||||
|
||||
types::StackTypeSet *objTypes = obj->resultTypeSet();
|
||||
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
|
||||
if (!TestShouldDOMCall(cx, objTypes, setter, JSJitInfo::Setter))
|
||||
return true;
|
||||
|
||||
@ -8644,7 +8645,7 @@ IonBuilder::setPropTryCommonDOMSetter(bool *emitted, MDefinition *obj,
|
||||
bool
|
||||
IonBuilder::setPropTryDefiniteSlot(bool *emitted, MDefinition *obj,
|
||||
HandlePropertyName name, MDefinition *value,
|
||||
bool barrier, types::StackTypeSet *objTypes)
|
||||
bool barrier, types::TemporaryTypeSet *objTypes)
|
||||
{
|
||||
JS_ASSERT(*emitted == false);
|
||||
|
||||
@ -8673,7 +8674,7 @@ bool
|
||||
IonBuilder::setPropTryInlineAccess(bool *emitted, MDefinition *obj,
|
||||
HandlePropertyName name, HandleId id,
|
||||
MDefinition *value, bool barrier,
|
||||
types::StackTypeSet *objTypes)
|
||||
types::TemporaryTypeSet *objTypes)
|
||||
{
|
||||
JS_ASSERT(*emitted == false);
|
||||
|
||||
@ -8736,7 +8737,7 @@ IonBuilder::setPropTryInlineAccess(bool *emitted, MDefinition *obj,
|
||||
bool
|
||||
IonBuilder::setPropTryCache(bool *emitted, MDefinition *obj,
|
||||
HandlePropertyName name, MDefinition *value,
|
||||
bool barrier, types::StackTypeSet *objTypes)
|
||||
bool barrier, types::TemporaryTypeSet *objTypes)
|
||||
{
|
||||
JS_ASSERT(*emitted == false);
|
||||
|
||||
@ -8889,7 +8890,7 @@ IonBuilder::jsop_this()
|
||||
return true;
|
||||
}
|
||||
|
||||
types::StackTypeSet *types = types::TypeScript::ThisTypes(script());
|
||||
types::TemporaryTypeSet *types = cloneTypeSet(types::TypeScript::ThisTypes(script()));
|
||||
if (types && (types->getKnownTypeTag() == JSVAL_TYPE_OBJECT ||
|
||||
(types->empty() && baselineFrame_ && baselineFrame_->thisValue().isObject())))
|
||||
{
|
||||
@ -9120,7 +9121,7 @@ IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc)
|
||||
current->add(load);
|
||||
current->push(load);
|
||||
|
||||
types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
types::TemporaryTypeSet *types = bytecodeTypes(pc);
|
||||
return pushTypeBarrier(load, types, true);
|
||||
}
|
||||
|
||||
@ -9234,7 +9235,7 @@ IonBuilder::jsop_instanceof()
|
||||
// If this is an 'x instanceof function' operation and we can determine the
|
||||
// exact function and prototype object being tested for, use a typed path.
|
||||
do {
|
||||
types::StackTypeSet *rhsTypes = rhs->resultTypeSet();
|
||||
types::TemporaryTypeSet *rhsTypes = rhs->resultTypeSet();
|
||||
JSObject *rhsObject = rhsTypes ? rhsTypes->getSingleton() : NULL;
|
||||
if (!rhsObject || !rhsObject->is<JSFunction>() || rhsObject->isBoundFunction())
|
||||
break;
|
||||
@ -9301,7 +9302,13 @@ IonBuilder::addShapeGuard(MDefinition *obj, Shape *const shape, BailoutKind bail
|
||||
return guard;
|
||||
}
|
||||
|
||||
types::StackTypeSet *
|
||||
types::TemporaryTypeSet *
|
||||
IonBuilder::bytecodeTypes(jsbytecode *pc)
|
||||
{
|
||||
return cloneTypeSet(types::TypeScript::BytecodeTypes(script(), pc));
|
||||
}
|
||||
|
||||
types::TemporaryTypeSet *
|
||||
IonBuilder::cloneTypeSet(types::StackTypeSet *types)
|
||||
{
|
||||
// Clone a type set so that it can be stored into the MIR and accessed
|
||||
|
@ -224,8 +224,8 @@ class IonBuilder : public MIRGenerator
|
||||
return js_IonOptions.inlining;
|
||||
}
|
||||
|
||||
JSFunction *getSingleCallTarget(types::StackTypeSet *calleeTypes);
|
||||
bool getPolyCallTargets(types::StackTypeSet *calleeTypes, bool constructing,
|
||||
JSFunction *getSingleCallTarget(types::TemporaryTypeSet *calleeTypes);
|
||||
bool getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constructing,
|
||||
AutoObjectVector &targets, uint32_t maxTargets, bool *gotLambda);
|
||||
bool canInlineTarget(JSFunction *target, bool constructing);
|
||||
|
||||
@ -294,7 +294,7 @@ class IonBuilder : public MIRGenerator
|
||||
// Incorporates a type/typeSet into an OSR value for a loop, after the loop
|
||||
// body has been processed.
|
||||
bool addOsrValueTypeBarrier(uint32_t slot, MInstruction **def,
|
||||
MIRType type, types::StackTypeSet *typeSet);
|
||||
MIRType type, types::TemporaryTypeSet *typeSet);
|
||||
bool maybeAddOsrTypeBarriers();
|
||||
|
||||
// Restarts processing of a loop if the type information at its header was
|
||||
@ -325,7 +325,7 @@ class IonBuilder : public MIRGenerator
|
||||
|
||||
// Add a guard which ensure that the set of type which goes through this
|
||||
// generated code correspond to the observed types for the bytecode.
|
||||
bool pushTypeBarrier(MInstruction *ins, types::StackTypeSet *observed, bool needBarrier);
|
||||
bool pushTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *observed, bool needBarrier);
|
||||
|
||||
JSObject *getSingletonPrototype(JSFunction *target);
|
||||
|
||||
@ -349,22 +349,22 @@ class IonBuilder : public MIRGenerator
|
||||
|
||||
bool hasStaticScopeObject(ScopeCoordinate sc, MutableHandleObject pcall);
|
||||
bool loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType,
|
||||
bool barrier, types::StackTypeSet *types);
|
||||
bool barrier, types::TemporaryTypeSet *types);
|
||||
bool storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier,
|
||||
MIRType slotType = MIRType_None);
|
||||
|
||||
// jsop_getprop() helpers.
|
||||
bool getPropTryArgumentsLength(bool *emitted);
|
||||
bool getPropTryConstant(bool *emitted, HandleId id, types::StackTypeSet *types);
|
||||
bool getPropTryConstant(bool *emitted, HandleId id, types::TemporaryTypeSet *types);
|
||||
bool getPropTryDefiniteSlot(bool *emitted, HandlePropertyName name,
|
||||
bool barrier, types::StackTypeSet *types);
|
||||
bool barrier, types::TemporaryTypeSet *types);
|
||||
bool getPropTryCommonGetter(bool *emitted, HandleId id,
|
||||
bool barrier, types::StackTypeSet *types);
|
||||
bool barrier, types::TemporaryTypeSet *types);
|
||||
bool getPropTryInlineAccess(bool *emitted, HandlePropertyName name, HandleId id,
|
||||
bool barrier, types::StackTypeSet *types);
|
||||
bool barrier, types::TemporaryTypeSet *types);
|
||||
bool getPropTryCache(bool *emitted, HandlePropertyName name, HandleId id,
|
||||
bool barrier, types::StackTypeSet *types);
|
||||
bool needsToMonitorMissingProperties(types::StackTypeSet *types);
|
||||
bool barrier, types::TemporaryTypeSet *types);
|
||||
bool needsToMonitorMissingProperties(types::TemporaryTypeSet *types);
|
||||
|
||||
// jsop_setprop() helpers.
|
||||
bool setPropTryCommonSetter(bool *emitted, MDefinition *obj,
|
||||
@ -375,14 +375,14 @@ class IonBuilder : public MIRGenerator
|
||||
bool isDOM);
|
||||
bool setPropTryDefiniteSlot(bool *emitted, MDefinition *obj,
|
||||
HandlePropertyName name, MDefinition *value,
|
||||
bool barrier, types::StackTypeSet *objTypes);
|
||||
bool barrier, types::TemporaryTypeSet *objTypes);
|
||||
bool setPropTryInlineAccess(bool *emitted, MDefinition *obj,
|
||||
HandlePropertyName name, HandleId id,
|
||||
MDefinition *value, bool barrier,
|
||||
types::StackTypeSet *objTypes);
|
||||
types::TemporaryTypeSet *objTypes);
|
||||
bool setPropTryCache(bool *emitted, MDefinition *obj,
|
||||
HandlePropertyName name, MDefinition *value,
|
||||
bool barrier, types::StackTypeSet *objTypes);
|
||||
bool barrier, types::TemporaryTypeSet *objTypes);
|
||||
|
||||
// jsop_setelem() helpers.
|
||||
bool setElemTryTyped(bool *emitted, MDefinition *object,
|
||||
@ -441,7 +441,7 @@ class IonBuilder : public MIRGenerator
|
||||
bool jsop_getelem_dense(MDefinition *obj, MDefinition *index);
|
||||
bool jsop_getelem_typed(MDefinition *obj, MDefinition *index, ScalarTypeRepresentation::Type arrayType);
|
||||
bool jsop_setelem();
|
||||
bool jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion,
|
||||
bool jsop_setelem_dense(types::TemporaryTypeSet::DoubleConversion conversion,
|
||||
SetElemSafety safety,
|
||||
MDefinition *object, MDefinition *index, MDefinition *value);
|
||||
bool jsop_setelem_typed(ScalarTypeRepresentation::Type arrayType,
|
||||
@ -497,7 +497,8 @@ class IonBuilder : public MIRGenerator
|
||||
uint32_t selectInliningTargets(AutoObjectVector &targets, CallInfo &callInfo, Vector<bool> &choiceSet);
|
||||
|
||||
// Native inlining helpers.
|
||||
types::StackTypeSet *getInlineReturnTypeSet();
|
||||
types::StackTypeSet *getOriginalInlineReturnTypeSet();
|
||||
types::TemporaryTypeSet *getInlineReturnTypeSet();
|
||||
MIRType getInlineReturnType();
|
||||
|
||||
// Array natives.
|
||||
@ -547,7 +548,7 @@ class IonBuilder : public MIRGenerator
|
||||
InliningStatus inlineParallelArrayTail(CallInfo &callInfo,
|
||||
HandleFunction target,
|
||||
MDefinition *ctor,
|
||||
types::StackTypeSet *ctorTypes,
|
||||
types::TemporaryTypeSet *ctorTypes,
|
||||
uint32_t discards);
|
||||
|
||||
// Utility intrinsics.
|
||||
@ -580,6 +581,8 @@ class IonBuilder : public MIRGenerator
|
||||
MTypeObjectDispatch *dispatch, MGetPropertyCache *cache,
|
||||
MBasicBlock **fallbackTarget);
|
||||
|
||||
bool testNeedsArgumentCheck(JSContext *cx, HandleFunction target, CallInfo &callInfo);
|
||||
|
||||
MDefinition *makeCallsiteClone(HandleFunction target, MDefinition *fun);
|
||||
MCall *makeCallHelper(HandleFunction target, CallInfo &callInfo, bool cloneAtCallsite);
|
||||
bool makeCall(HandleFunction target, CallInfo &callInfo, bool cloneAtCallsite);
|
||||
@ -587,17 +590,18 @@ class IonBuilder : public MIRGenerator
|
||||
MDefinition *patchInlinedReturn(CallInfo &callInfo, MBasicBlock *exit, MBasicBlock *bottom);
|
||||
MDefinition *patchInlinedReturns(CallInfo &callInfo, MIRGraphExits &exits, MBasicBlock *bottom);
|
||||
|
||||
inline bool TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types,
|
||||
inline bool TestCommonPropFunc(JSContext *cx, types::TemporaryTypeSet *types,
|
||||
HandleId id, JSFunction **funcp,
|
||||
bool isGetter, bool *isDOM,
|
||||
MDefinition **guardOut);
|
||||
|
||||
bool annotateGetPropertyCache(JSContext *cx, MDefinition *obj, MGetPropertyCache *getPropCache,
|
||||
types::StackTypeSet *objTypes, types::StackTypeSet *pushedTypes);
|
||||
types::TemporaryTypeSet *objTypes, types::TemporaryTypeSet *pushedTypes);
|
||||
|
||||
MGetPropertyCache *getInlineableGetPropertyCache(CallInfo &callInfo);
|
||||
|
||||
types::StackTypeSet *cloneTypeSet(types::StackTypeSet *types);
|
||||
types::TemporaryTypeSet *bytecodeTypes(jsbytecode *pc);
|
||||
types::TemporaryTypeSet *cloneTypeSet(types::StackTypeSet *types);
|
||||
|
||||
// Use one of the below methods for updating the current block, rather than
|
||||
// updating |current| directly. setCurrent() should only be used in cases
|
||||
|
@ -138,9 +138,9 @@ MacroAssembler::guardType(const Source &address, types::Type type,
|
||||
guardTypeSet(address, &wrapper, scratch, matched, miss);
|
||||
}
|
||||
|
||||
template void MacroAssembler::guardTypeSet(const Address &address, const types::StackTypeSet *types,
|
||||
template void MacroAssembler::guardTypeSet(const Address &address, const types::TemporaryTypeSet *types,
|
||||
Register scratch, Label *matched, Label *miss);
|
||||
template void MacroAssembler::guardTypeSet(const ValueOperand &value, const types::StackTypeSet *types,
|
||||
template void MacroAssembler::guardTypeSet(const ValueOperand &value, const types::TemporaryTypeSet *types,
|
||||
Register scratch, Label *matched, Label *miss);
|
||||
|
||||
template void MacroAssembler::guardTypeSet(const Address &address, const types::HeapTypeSet *types,
|
||||
@ -160,7 +160,7 @@ template void MacroAssembler::guardTypeSet(const Address &address, const TypeWra
|
||||
template void MacroAssembler::guardTypeSet(const ValueOperand &value, const TypeWrapper *types,
|
||||
Register scratch, Label *matched, Label *miss);
|
||||
|
||||
template void MacroAssembler::guardObjectType(Register obj, const types::StackTypeSet *types,
|
||||
template void MacroAssembler::guardObjectType(Register obj, const types::TemporaryTypeSet *types,
|
||||
Register scratch, Label *matched, Label *miss);
|
||||
template void MacroAssembler::guardObjectType(Register obj, const types::TypeSet *types,
|
||||
Register scratch, Label *matched, Label *miss);
|
||||
|
@ -1951,7 +1951,7 @@ LIRGenerator::visitTypeBarrier(MTypeBarrier *ins)
|
||||
// Requesting a non-GC pointer is safe here since we never re-enter C++
|
||||
// from inside a type barrier test.
|
||||
|
||||
const types::StackTypeSet *types = ins->resultTypeSet();
|
||||
const types::TemporaryTypeSet *types = ins->resultTypeSet();
|
||||
bool needTemp = !types->unknownObject() && types->getObjectCount() > 0;
|
||||
|
||||
MIRType inputType = ins->getOperand(0)->type();
|
||||
@ -2002,7 +2002,7 @@ LIRGenerator::visitMonitorTypes(MMonitorTypes *ins)
|
||||
// Requesting a non-GC pointer is safe here since we never re-enter C++
|
||||
// from inside a type check.
|
||||
|
||||
const types::StackTypeSet *types = ins->typeSet();
|
||||
const types::TemporaryTypeSet *types = ins->typeSet();
|
||||
bool needTemp = !types->unknownObject() && types->getObjectCount() > 0;
|
||||
LDefinition tmp = needTemp ? temp() : tempToUnbox();
|
||||
|
||||
|
@ -159,15 +159,21 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native)
|
||||
}
|
||||
|
||||
types::StackTypeSet *
|
||||
IonBuilder::getInlineReturnTypeSet()
|
||||
IonBuilder::getOriginalInlineReturnTypeSet()
|
||||
{
|
||||
return types::TypeScript::BytecodeTypes(script(), pc);
|
||||
}
|
||||
|
||||
types::TemporaryTypeSet *
|
||||
IonBuilder::getInlineReturnTypeSet()
|
||||
{
|
||||
return cloneTypeSet(getOriginalInlineReturnTypeSet());
|
||||
}
|
||||
|
||||
MIRType
|
||||
IonBuilder::getInlineReturnType()
|
||||
{
|
||||
types::StackTypeSet *returnTypes = getInlineReturnTypeSet();
|
||||
types::TemporaryTypeSet *returnTypes = getInlineReturnTypeSet();
|
||||
return MIRTypeFromValueType(returnTypes->getKnownTypeTag());
|
||||
}
|
||||
|
||||
@ -246,9 +252,9 @@ IonBuilder::inlineArray(CallInfo &callInfo)
|
||||
if (!templateObject)
|
||||
return InliningStatus_Error;
|
||||
|
||||
types::StackTypeSet::DoubleConversion conversion =
|
||||
types::TemporaryTypeSet::DoubleConversion conversion =
|
||||
getInlineReturnTypeSet()->convertDoubleElements(cx);
|
||||
if (conversion == types::StackTypeSet::AlwaysConvertToDoubles)
|
||||
if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
|
||||
templateObject->setShouldConvertDoubleElements();
|
||||
|
||||
MNewArray *ins = new MNewArray(initLength, templateObject, allocating);
|
||||
@ -271,7 +277,7 @@ IonBuilder::inlineArray(CallInfo &callInfo)
|
||||
current->add(id);
|
||||
|
||||
MDefinition *value = callInfo.getArg(i);
|
||||
if (conversion == types::StackTypeSet::AlwaysConvertToDoubles) {
|
||||
if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles) {
|
||||
MInstruction *valueDouble = MToDouble::New(value);
|
||||
current->add(valueDouble);
|
||||
value = valueDouble;
|
||||
@ -313,7 +319,7 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
|
||||
types::OBJECT_FLAG_LENGTH_OVERFLOW |
|
||||
types::OBJECT_FLAG_ITERATED;
|
||||
|
||||
types::StackTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
|
||||
types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
|
||||
if (!thisTypes || thisTypes->getKnownClass() != &ArrayObject::class_)
|
||||
return InliningStatus_NotInlined;
|
||||
if (thisTypes->hasObjectFlags(cx, unhandledFlags))
|
||||
@ -324,7 +330,7 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
|
||||
|
||||
callInfo.unwrapArgs();
|
||||
|
||||
types::StackTypeSet *returnTypes = getInlineReturnTypeSet();
|
||||
types::StackTypeSet *returnTypes = getOriginalInlineReturnTypeSet();
|
||||
bool needsHoleCheck = thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED);
|
||||
bool maybeUndefined = returnTypes->hasType(types::Type::UndefinedType());
|
||||
|
||||
@ -344,7 +350,7 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
|
||||
if (!resumeAfter(ins))
|
||||
return InliningStatus_Error;
|
||||
|
||||
if (!pushTypeBarrier(ins, returnTypes, barrier))
|
||||
if (!pushTypeBarrier(ins, cloneTypeSet(returnTypes), barrier))
|
||||
return InliningStatus_Error;
|
||||
|
||||
return InliningStatus_Inlined;
|
||||
@ -373,7 +379,7 @@ IonBuilder::inlineArrayPush(CallInfo &callInfo)
|
||||
if (callInfo.thisArg()->type() != MIRType_Object)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
types::StackTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
|
||||
types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
|
||||
if (!thisTypes || thisTypes->getKnownClass() != &ArrayObject::class_)
|
||||
return InliningStatus_NotInlined;
|
||||
if (thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPARSE_INDEXES |
|
||||
@ -385,15 +391,15 @@ IonBuilder::inlineArrayPush(CallInfo &callInfo)
|
||||
if (types::ArrayPrototypeHasIndexedProperty(cx, script))
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
types::StackTypeSet::DoubleConversion conversion = thisTypes->convertDoubleElements(cx);
|
||||
if (conversion == types::StackTypeSet::AmbiguousDoubleConversion)
|
||||
types::TemporaryTypeSet::DoubleConversion conversion = thisTypes->convertDoubleElements(cx);
|
||||
if (conversion == types::TemporaryTypeSet::AmbiguousDoubleConversion)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
callInfo.unwrapArgs();
|
||||
value = callInfo.getArg(0);
|
||||
|
||||
if (conversion == types::StackTypeSet::AlwaysConvertToDoubles ||
|
||||
conversion == types::StackTypeSet::MaybeConvertToDoubles)
|
||||
if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles ||
|
||||
conversion == types::TemporaryTypeSet::MaybeConvertToDoubles)
|
||||
{
|
||||
MInstruction *valueDouble = MToDouble::New(value);
|
||||
current->add(valueDouble);
|
||||
@ -427,8 +433,8 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
// |this| and the argument must be dense arrays.
|
||||
types::StackTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
|
||||
types::StackTypeSet *argTypes = callInfo.getArg(0)->resultTypeSet();
|
||||
types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
|
||||
types::TemporaryTypeSet *argTypes = callInfo.getArg(0)->resultTypeSet();
|
||||
if (!thisTypes || !argTypes)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
@ -481,7 +487,7 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo)
|
||||
if (!thisElemTypes)
|
||||
return InliningStatus_Error;
|
||||
|
||||
types::StackTypeSet *resTypes = getInlineReturnTypeSet();
|
||||
types::TemporaryTypeSet *resTypes = getInlineReturnTypeSet();
|
||||
if (!resTypes->hasType(types::Type::ObjectType(thisType)))
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
@ -1001,7 +1007,7 @@ IonBuilder::inlineRegExpTest(CallInfo &callInfo)
|
||||
|
||||
if (callInfo.thisArg()->type() != MIRType_Object)
|
||||
return InliningStatus_NotInlined;
|
||||
types::StackTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
|
||||
types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
|
||||
const Class *clasp = thisTypes ? thisTypes->getKnownClass() : NULL;
|
||||
if (clasp != &RegExpObject::class_)
|
||||
return InliningStatus_NotInlined;
|
||||
@ -1113,7 +1119,7 @@ IonBuilder::inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base)
|
||||
MDefinition *id = callInfo.getArg(base + 1);
|
||||
MDefinition *elem = callInfo.getArg(base + 2);
|
||||
|
||||
types::StackTypeSet::DoubleConversion conversion =
|
||||
types::TemporaryTypeSet::DoubleConversion conversion =
|
||||
obj->resultTypeSet()->convertDoubleElements(cx);
|
||||
if (!jsop_setelem_dense(conversion, SetElem_Unsafe, obj, id, elem))
|
||||
return false;
|
||||
@ -1186,7 +1192,7 @@ IonBuilder::inlineNewParallelArray(CallInfo &callInfo)
|
||||
if (argc < 1 || callInfo.constructing())
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
types::StackTypeSet *ctorTypes = callInfo.getArg(0)->resultTypeSet();
|
||||
types::TemporaryTypeSet *ctorTypes = callInfo.getArg(0)->resultTypeSet();
|
||||
JSObject *targetObj = ctorTypes ? ctorTypes->getSingleton() : NULL;
|
||||
RootedFunction target(cx);
|
||||
if (targetObj && targetObj->is<JSFunction>())
|
||||
@ -1233,7 +1239,7 @@ IonBuilder::InliningStatus
|
||||
IonBuilder::inlineParallelArrayTail(CallInfo &callInfo,
|
||||
HandleFunction target,
|
||||
MDefinition *ctor,
|
||||
types::StackTypeSet *ctorTypes,
|
||||
types::TemporaryTypeSet *ctorTypes,
|
||||
uint32_t discards)
|
||||
{
|
||||
// Rewrites either NewParallelArray(...) or new ParallelArray(...) from a
|
||||
@ -1245,7 +1251,7 @@ IonBuilder::inlineParallelArrayTail(CallInfo &callInfo,
|
||||
// Create the new parallel array object. Parallel arrays have specially
|
||||
// constructed type objects, so we can only perform the inlining if we
|
||||
// already have one of these type objects.
|
||||
types::StackTypeSet *returnTypes = getInlineReturnTypeSet();
|
||||
types::TemporaryTypeSet *returnTypes = getInlineReturnTypeSet();
|
||||
if (returnTypes->getKnownTypeTag() != JSVAL_TYPE_OBJECT)
|
||||
return InliningStatus_NotInlined;
|
||||
if (returnTypes->unknownObject() || returnTypes->getObjectCount() != 1)
|
||||
@ -1358,7 +1364,7 @@ IonBuilder::inlineNewDenseArrayForParallelExecution(CallInfo &callInfo)
|
||||
// Create the new parallel array object. Parallel arrays have specially
|
||||
// constructed type objects, so we can only perform the inlining if we
|
||||
// already have one of these type objects.
|
||||
types::StackTypeSet *returnTypes = getInlineReturnTypeSet();
|
||||
types::TemporaryTypeSet *returnTypes = getInlineReturnTypeSet();
|
||||
if (returnTypes->getKnownTypeTag() != JSVAL_TYPE_OBJECT)
|
||||
return InliningStatus_NotInlined;
|
||||
if (returnTypes->unknownObject() || returnTypes->getObjectCount() != 1)
|
||||
@ -1476,8 +1482,8 @@ IonBuilder::inlineHaveSameClass(CallInfo &callInfo)
|
||||
if (callInfo.getArg(1)->type() != MIRType_Object)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
types::StackTypeSet *arg1Types = callInfo.getArg(0)->resultTypeSet();
|
||||
types::StackTypeSet *arg2Types = callInfo.getArg(1)->resultTypeSet();
|
||||
types::TemporaryTypeSet *arg1Types = callInfo.getArg(0)->resultTypeSet();
|
||||
types::TemporaryTypeSet *arg2Types = callInfo.getArg(1)->resultTypeSet();
|
||||
const Class *arg1Clasp = arg1Types ? arg1Types->getKnownClass() : NULL;
|
||||
const Class *arg2Clasp = arg2Types ? arg2Types->getKnownClass() : NULL;
|
||||
if (arg1Clasp && arg2Clasp) {
|
||||
@ -1515,7 +1521,7 @@ IonBuilder::inlineIsCallable(CallInfo &callInfo)
|
||||
isCallableKnown = true;
|
||||
isCallableConstant = false;
|
||||
} else {
|
||||
types::StackTypeSet *types = callInfo.getArg(0)->resultTypeSet();
|
||||
types::TemporaryTypeSet *types = callInfo.getArg(0)->resultTypeSet();
|
||||
const Class *clasp = types ? types->getKnownClass() : NULL;
|
||||
if (clasp) {
|
||||
isCallableKnown = true;
|
||||
|
@ -204,7 +204,7 @@ MaybeEmulatesUndefined(JSContext *cx, MDefinition *op)
|
||||
if (!op->mightBeType(MIRType_Object))
|
||||
return false;
|
||||
|
||||
types::StackTypeSet *types = op->resultTypeSet();
|
||||
types::TemporaryTypeSet *types = op->resultTypeSet();
|
||||
if (!types)
|
||||
return true;
|
||||
|
||||
@ -219,7 +219,7 @@ MaybeCallable(JSContext *cx, MDefinition *op)
|
||||
if (!op->mightBeType(MIRType_Object))
|
||||
return false;
|
||||
|
||||
types::StackTypeSet *types = op->resultTypeSet();
|
||||
types::TemporaryTypeSet *types = op->resultTypeSet();
|
||||
if (!types)
|
||||
return true;
|
||||
|
||||
@ -402,16 +402,11 @@ MConstant::New(const Value &v)
|
||||
return new MConstant(v);
|
||||
}
|
||||
|
||||
types::StackTypeSet *
|
||||
types::TemporaryTypeSet *
|
||||
jit::MakeSingletonTypeSet(JSObject *obj)
|
||||
{
|
||||
LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
|
||||
types::StackTypeSet *types = alloc->new_<types::StackTypeSet>();
|
||||
if (!types)
|
||||
return NULL;
|
||||
types::Type objectType = types::Type::ObjectType(obj);
|
||||
types->addObject(objectType.objectKey(), alloc);
|
||||
return types;
|
||||
return alloc->new_<types::TemporaryTypeSet>(types::Type::ObjectType(obj));
|
||||
}
|
||||
|
||||
MConstant::MConstant(const js::Value &vp)
|
||||
@ -545,7 +540,7 @@ MConstantElements::printOpcode(FILE *fp) const
|
||||
}
|
||||
|
||||
MParameter *
|
||||
MParameter::New(int32_t index, types::StackTypeSet *types)
|
||||
MParameter::New(int32_t index, types::TemporaryTypeSet *types)
|
||||
{
|
||||
return new MParameter(index, types);
|
||||
}
|
||||
@ -768,19 +763,19 @@ MPhi::reserveLength(size_t length)
|
||||
return inputs_.reserve(length);
|
||||
}
|
||||
|
||||
static inline types::StackTypeSet *
|
||||
static inline types::TemporaryTypeSet *
|
||||
MakeMIRTypeSet(MIRType type)
|
||||
{
|
||||
JS_ASSERT(type != MIRType_Value);
|
||||
types::Type ntype = type == MIRType_Object
|
||||
? types::Type::AnyObjectType()
|
||||
: types::Type::PrimitiveType(ValueTypeFromMIRType(type));
|
||||
return GetIonContext()->temp->lifoAlloc()->new_<types::StackTypeSet>(ntype);
|
||||
return GetIonContext()->temp->lifoAlloc()->new_<types::TemporaryTypeSet>(ntype);
|
||||
}
|
||||
|
||||
void
|
||||
jit::MergeTypes(MIRType *ptype, types::StackTypeSet **ptypeSet,
|
||||
MIRType newType, types::StackTypeSet *newTypeSet)
|
||||
jit::MergeTypes(MIRType *ptype, types::TemporaryTypeSet **ptypeSet,
|
||||
MIRType newType, types::TemporaryTypeSet *newTypeSet)
|
||||
{
|
||||
if (newTypeSet && newTypeSet->empty())
|
||||
return;
|
||||
@ -832,7 +827,7 @@ MPhi::specializeType()
|
||||
}
|
||||
|
||||
MIRType resultType = this->type();
|
||||
types::StackTypeSet *resultTypeSet = this->resultTypeSet();
|
||||
types::TemporaryTypeSet *resultTypeSet = this->resultTypeSet();
|
||||
|
||||
for (size_t i = start; i < inputs_.length(); i++) {
|
||||
MDefinition *def = getOperand(i);
|
||||
@ -844,13 +839,13 @@ MPhi::specializeType()
|
||||
}
|
||||
|
||||
void
|
||||
MPhi::addBackedgeType(MIRType type, types::StackTypeSet *typeSet)
|
||||
MPhi::addBackedgeType(MIRType type, types::TemporaryTypeSet *typeSet)
|
||||
{
|
||||
JS_ASSERT(!specialized_);
|
||||
|
||||
if (hasBackedgeType_) {
|
||||
MIRType resultType = this->type();
|
||||
types::StackTypeSet *resultTypeSet = this->resultTypeSet();
|
||||
types::TemporaryTypeSet *resultTypeSet = this->resultTypeSet();
|
||||
|
||||
MergeTypes(&resultType, &resultTypeSet, type, typeSet);
|
||||
|
||||
@ -869,7 +864,7 @@ MPhi::typeIncludes(MDefinition *def)
|
||||
if (def->type() == MIRType_Int32 && this->type() == MIRType_Double)
|
||||
return true;
|
||||
|
||||
if (types::StackTypeSet *types = def->resultTypeSet()) {
|
||||
if (types::TemporaryTypeSet *types = def->resultTypeSet()) {
|
||||
if (this->resultTypeSet())
|
||||
return types->isSubset(this->resultTypeSet());
|
||||
if (this->type() == MIRType_Value || types->empty())
|
||||
@ -926,7 +921,7 @@ MPhi::addInputSlow(MDefinition *ins, bool *ptypeChange)
|
||||
|
||||
if (ptypeChange) {
|
||||
MIRType resultType = this->type();
|
||||
types::StackTypeSet *resultTypeSet = this->resultTypeSet();
|
||||
types::TemporaryTypeSet *resultTypeSet = this->resultTypeSet();
|
||||
|
||||
MergeTypes(&resultType, &resultTypeSet, ins->type(), ins->resultTypeSet());
|
||||
|
||||
@ -1564,7 +1559,7 @@ MBinaryArithInstruction::inferFallback(BaselineInspector *inspector,
|
||||
// either to avoid degrading subsequent analysis.
|
||||
if (getOperand(0)->emptyResultTypeSet() || getOperand(1)->emptyResultTypeSet()) {
|
||||
LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
|
||||
types::StackTypeSet *types = alloc->new_<types::StackTypeSet>();
|
||||
types::TemporaryTypeSet *types = alloc->new_<types::TemporaryTypeSet>();
|
||||
if (types)
|
||||
setResultTypeSet(types);
|
||||
}
|
||||
@ -2501,11 +2496,11 @@ InlinePropertyTable::hasFunction(JSFunction *func) const
|
||||
return false;
|
||||
}
|
||||
|
||||
types::StackTypeSet *
|
||||
types::TemporaryTypeSet *
|
||||
InlinePropertyTable::buildTypeSetForFunction(JSFunction *func) const
|
||||
{
|
||||
LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
|
||||
types::StackTypeSet *types = alloc->new_<types::StackTypeSet>();
|
||||
types::TemporaryTypeSet *types = alloc->new_<types::TemporaryTypeSet>();
|
||||
if (!types)
|
||||
return NULL;
|
||||
for (size_t i = 0; i < numEntries(); i++) {
|
||||
@ -2640,7 +2635,7 @@ jit::ElementAccessIsDenseNative(MDefinition *obj, MDefinition *id)
|
||||
if (id->type() != MIRType_Int32 && id->type() != MIRType_Double)
|
||||
return false;
|
||||
|
||||
types::StackTypeSet *types = obj->resultTypeSet();
|
||||
types::TemporaryTypeSet *types = obj->resultTypeSet();
|
||||
if (!types)
|
||||
return false;
|
||||
|
||||
@ -2658,7 +2653,7 @@ jit::ElementAccessIsTypedArray(MDefinition *obj, MDefinition *id,
|
||||
if (id->type() != MIRType_Int32 && id->type() != MIRType_Double)
|
||||
return false;
|
||||
|
||||
types::StackTypeSet *types = obj->resultTypeSet();
|
||||
types::TemporaryTypeSet *types = obj->resultTypeSet();
|
||||
if (!types)
|
||||
return false;
|
||||
|
||||
@ -2669,14 +2664,14 @@ jit::ElementAccessIsTypedArray(MDefinition *obj, MDefinition *id,
|
||||
bool
|
||||
jit::ElementAccessIsPacked(JSContext *cx, MDefinition *obj)
|
||||
{
|
||||
types::StackTypeSet *types = obj->resultTypeSet();
|
||||
types::TemporaryTypeSet *types = obj->resultTypeSet();
|
||||
return types && !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED);
|
||||
}
|
||||
|
||||
bool
|
||||
jit::ElementAccessHasExtraIndexedProperty(JSContext *cx, MDefinition *obj)
|
||||
{
|
||||
types::StackTypeSet *types = obj->resultTypeSet();
|
||||
types::TemporaryTypeSet *types = obj->resultTypeSet();
|
||||
|
||||
if (!types || types->hasObjectFlags(cx, types::OBJECT_FLAG_LENGTH_OVERFLOW))
|
||||
return true;
|
||||
@ -2690,7 +2685,7 @@ jit::DenseNativeElementType(JSContext *cx, MDefinition *obj, MIRType *result)
|
||||
JS_ASSERT(result);
|
||||
*result = MIRType_None;
|
||||
|
||||
types::StackTypeSet *types = obj->resultTypeSet();
|
||||
types::TemporaryTypeSet *types = obj->resultTypeSet();
|
||||
MIRType elementType = MIRType_None;
|
||||
unsigned count = types->getObjectCount();
|
||||
|
||||
@ -2877,7 +2872,7 @@ jit::AddObjectsForPropertyRead(JSContext *cx, MDefinition *obj, PropertyName *na
|
||||
|
||||
JS_ASSERT(observed->noConstraints());
|
||||
|
||||
types::StackTypeSet *types = obj->resultTypeSet();
|
||||
types::TemporaryTypeSet *types = obj->resultTypeSet();
|
||||
if (!types || types->unknownObject()) {
|
||||
observed->addType(cx, types::Type::AnyObjectType());
|
||||
return true;
|
||||
@ -2916,7 +2911,7 @@ jit::AddObjectsForPropertyRead(JSContext *cx, MDefinition *obj, PropertyName *na
|
||||
}
|
||||
|
||||
static bool
|
||||
TryAddTypeBarrierForWrite(JSContext *cx, MBasicBlock *current, types::StackTypeSet *objTypes,
|
||||
TryAddTypeBarrierForWrite(JSContext *cx, MBasicBlock *current, types::TemporaryTypeSet *objTypes,
|
||||
jsid id, MDefinition **pvalue)
|
||||
{
|
||||
// Return whether pvalue was modified to include a type barrier ensuring
|
||||
@ -2986,7 +2981,7 @@ TryAddTypeBarrierForWrite(JSContext *cx, MBasicBlock *current, types::StackTypeS
|
||||
if ((*pvalue)->type() != MIRType_Value)
|
||||
return false;
|
||||
|
||||
types::StackTypeSet *types = aggregateProperty->clone(GetIonContext()->temp->lifoAlloc());
|
||||
types::TemporaryTypeSet *types = aggregateProperty->clone(GetIonContext()->temp->lifoAlloc());
|
||||
if (!types)
|
||||
return false;
|
||||
|
||||
@ -3022,7 +3017,7 @@ jit::PropertyWriteNeedsTypeBarrier(JSContext *cx, MBasicBlock *current, MDefinit
|
||||
// properties that are accounted for by type information, i.e. normal data
|
||||
// properties and elements.
|
||||
|
||||
types::StackTypeSet *types = (*pobj)->resultTypeSet();
|
||||
types::TemporaryTypeSet *types = (*pobj)->resultTypeSet();
|
||||
if (!types || types->unknownObject()) {
|
||||
*result = true;
|
||||
return true;
|
||||
|
@ -283,7 +283,7 @@ class MDefinition : public MNode
|
||||
ValueNumberData *valueNumber_; // The instruction's value number (see GVN for details in use)
|
||||
Range *range_; // Any computed range for this def.
|
||||
MIRType resultType_; // Representation of result type.
|
||||
types::StackTypeSet *resultTypeSet_; // Optional refinement of the result type.
|
||||
types::TemporaryTypeSet *resultTypeSet_; // Optional refinement of the result type.
|
||||
uint32_t flags_; // Bit flags.
|
||||
union {
|
||||
MDefinition *dependency_; // Implicit dependency (store, call, etc.) of this instruction.
|
||||
@ -436,7 +436,7 @@ class MDefinition : public MNode
|
||||
return resultType_;
|
||||
}
|
||||
|
||||
types::StackTypeSet *resultTypeSet() const {
|
||||
types::TemporaryTypeSet *resultTypeSet() const {
|
||||
return resultTypeSet_;
|
||||
}
|
||||
bool emptyResultTypeSet() const;
|
||||
@ -548,7 +548,7 @@ class MDefinition : public MNode
|
||||
void setResultType(MIRType type) {
|
||||
resultType_ = type;
|
||||
}
|
||||
void setResultTypeSet(types::StackTypeSet *types) {
|
||||
void setResultTypeSet(types::TemporaryTypeSet *types) {
|
||||
resultTypeSet_ = types;
|
||||
}
|
||||
|
||||
@ -979,7 +979,7 @@ class MParameter : public MNullaryInstruction
|
||||
public:
|
||||
static const int32_t THIS_SLOT = -1;
|
||||
|
||||
MParameter(int32_t index, types::StackTypeSet *types)
|
||||
MParameter(int32_t index, types::TemporaryTypeSet *types)
|
||||
: index_(index)
|
||||
{
|
||||
setResultType(MIRType_Value);
|
||||
@ -988,7 +988,7 @@ class MParameter : public MNullaryInstruction
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(Parameter)
|
||||
static MParameter *New(int32_t index, types::StackTypeSet *types);
|
||||
static MParameter *New(int32_t index, types::TemporaryTypeSet *types);
|
||||
|
||||
int32_t index() const {
|
||||
return index_;
|
||||
@ -1354,12 +1354,12 @@ class MNewParallelArray : public MNullaryInstruction
|
||||
};
|
||||
|
||||
// Fabricate a type set containing only the type of the specified object.
|
||||
types::StackTypeSet *
|
||||
types::TemporaryTypeSet *
|
||||
MakeSingletonTypeSet(JSObject *obj);
|
||||
|
||||
void
|
||||
MergeTypes(MIRType *ptype, types::StackTypeSet **ptypeSet,
|
||||
MIRType newType, types::StackTypeSet *newTypeSet);
|
||||
MergeTypes(MIRType *ptype, types::TemporaryTypeSet **ptypeSet,
|
||||
MIRType newType, types::TemporaryTypeSet *newTypeSet);
|
||||
|
||||
class MNewArray : public MNullaryInstruction
|
||||
{
|
||||
@ -2133,7 +2133,7 @@ class MBox : public MUnaryInstruction
|
||||
types::Type ntype = ins->type() == MIRType_Object
|
||||
? types::Type::AnyObjectType()
|
||||
: types::Type::PrimitiveType(ValueTypeFromMIRType(ins->type()));
|
||||
setResultTypeSet(GetIonContext()->temp->lifoAlloc()->new_<types::StackTypeSet>(ntype));
|
||||
setResultTypeSet(GetIonContext()->temp->lifoAlloc()->new_<types::TemporaryTypeSet>(ntype));
|
||||
}
|
||||
setMovable();
|
||||
}
|
||||
@ -4076,7 +4076,7 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineForwardListNode<MPhi>
|
||||
|
||||
// Add types for this phi which speculate about new inputs that may come in
|
||||
// via a loop backedge.
|
||||
void addBackedgeType(MIRType type, types::StackTypeSet *typeSet);
|
||||
void addBackedgeType(MIRType type, types::TemporaryTypeSet *typeSet);
|
||||
|
||||
// Initializes the operands vector to the given capacity,
|
||||
// permitting use of addInput() instead of addInputSlow().
|
||||
@ -4454,7 +4454,7 @@ class MLambdaPar
|
||||
CompilerRootFunction fun_;
|
||||
|
||||
MLambdaPar(MDefinition *slice, MDefinition *scopeChain, JSFunction *fun,
|
||||
types::StackTypeSet *resultTypes)
|
||||
types::TemporaryTypeSet *resultTypes)
|
||||
: MBinaryInstruction(slice, scopeChain), fun_(fun)
|
||||
{
|
||||
JS_ASSERT(!fun->hasSingletonType());
|
||||
@ -5886,7 +5886,7 @@ class InlinePropertyTable : public TempObject
|
||||
}
|
||||
|
||||
bool hasFunction(JSFunction *func) const;
|
||||
types::StackTypeSet *buildTypeSetForFunction(JSFunction *func) const;
|
||||
types::TemporaryTypeSet *buildTypeSetForFunction(JSFunction *func) const;
|
||||
|
||||
// Remove targets that vetoed inlining from the InlinePropertyTable.
|
||||
void trimTo(AutoObjectVector &targets, Vector<bool> &choiceSet);
|
||||
@ -7676,7 +7676,7 @@ class MRestPar
|
||||
public IntPolicy<1>
|
||||
{
|
||||
MRestPar(MDefinition *slice, MDefinition *numActuals, unsigned numFormals,
|
||||
JSObject *templateObject, types::StackTypeSet *resultTypes)
|
||||
JSObject *templateObject, types::TemporaryTypeSet *resultTypes)
|
||||
: MBinaryInstruction(slice, numActuals),
|
||||
MRestCommon(numFormals, templateObject)
|
||||
{
|
||||
@ -7759,7 +7759,7 @@ class MTypeBarrier
|
||||
{
|
||||
BailoutKind bailoutKind_;
|
||||
|
||||
MTypeBarrier(MDefinition *def, types::StackTypeSet *types, BailoutKind bailoutKind)
|
||||
MTypeBarrier(MDefinition *def, types::TemporaryTypeSet *types, BailoutKind bailoutKind)
|
||||
: MUnaryInstruction(def)
|
||||
{
|
||||
JS_ASSERT(!types->unknown());
|
||||
@ -7776,11 +7776,11 @@ class MTypeBarrier
|
||||
public:
|
||||
INSTRUCTION_HEADER(TypeBarrier)
|
||||
|
||||
static MTypeBarrier *New(MDefinition *def, types::StackTypeSet *types) {
|
||||
static MTypeBarrier *New(MDefinition *def, types::TemporaryTypeSet *types) {
|
||||
BailoutKind kind = def->isEffectful() ? Bailout_TypeBarrier : Bailout_Normal;
|
||||
return new MTypeBarrier(def, types, kind);
|
||||
}
|
||||
static MTypeBarrier *New(MDefinition *def, types::StackTypeSet *types,
|
||||
static MTypeBarrier *New(MDefinition *def, types::TemporaryTypeSet *types,
|
||||
BailoutKind kind) {
|
||||
return new MTypeBarrier(def, types, kind);
|
||||
}
|
||||
@ -7821,9 +7821,9 @@ class MTypeBarrier
|
||||
// in the property types for the object.
|
||||
class MMonitorTypes : public MUnaryInstruction, public BoxInputsPolicy
|
||||
{
|
||||
const types::StackTypeSet *typeSet_;
|
||||
const types::TemporaryTypeSet *typeSet_;
|
||||
|
||||
MMonitorTypes(MDefinition *def, const types::StackTypeSet *types)
|
||||
MMonitorTypes(MDefinition *def, const types::TemporaryTypeSet *types)
|
||||
: MUnaryInstruction(def),
|
||||
typeSet_(types)
|
||||
{
|
||||
@ -7834,7 +7834,7 @@ class MMonitorTypes : public MUnaryInstruction, public BoxInputsPolicy
|
||||
public:
|
||||
INSTRUCTION_HEADER(MonitorTypes)
|
||||
|
||||
static MMonitorTypes *New(MDefinition *def, const types::StackTypeSet *types) {
|
||||
static MMonitorTypes *New(MDefinition *def, const types::TemporaryTypeSet *types) {
|
||||
return new MMonitorTypes(def, types);
|
||||
}
|
||||
|
||||
@ -7842,7 +7842,7 @@ class MMonitorTypes : public MUnaryInstruction, public BoxInputsPolicy
|
||||
return this;
|
||||
}
|
||||
|
||||
const types::StackTypeSet *typeSet() const {
|
||||
const types::TemporaryTypeSet *typeSet() const {
|
||||
return typeSet_;
|
||||
}
|
||||
AliasSet getAliasSet() const {
|
||||
|
@ -773,7 +773,7 @@ ParallelSafetyVisitor::visitThrow(MThrow *thr)
|
||||
|
||||
static bool
|
||||
GetPossibleCallees(JSContext *cx, HandleScript script, jsbytecode *pc,
|
||||
types::StackTypeSet *calleeTypes, CallTargetVector &targets);
|
||||
types::TemporaryTypeSet *calleeTypes, CallTargetVector &targets);
|
||||
|
||||
static bool
|
||||
AddCallTarget(HandleScript script, CallTargetVector &targets);
|
||||
@ -804,7 +804,7 @@ jit::AddPossibleCallees(MIRGraph &graph, CallTargetVector &targets)
|
||||
continue;
|
||||
}
|
||||
|
||||
types::StackTypeSet *calleeTypes = callIns->getFunction()->resultTypeSet();
|
||||
types::TemporaryTypeSet *calleeTypes = callIns->getFunction()->resultTypeSet();
|
||||
RootedScript script(cx, callIns->block()->info().script());
|
||||
if (!GetPossibleCallees(cx,
|
||||
script,
|
||||
@ -822,7 +822,7 @@ static bool
|
||||
GetPossibleCallees(JSContext *cx,
|
||||
HandleScript script,
|
||||
jsbytecode *pc,
|
||||
types::StackTypeSet *calleeTypes,
|
||||
types::TemporaryTypeSet *calleeTypes,
|
||||
CallTargetVector &targets)
|
||||
{
|
||||
if (!calleeTypes || calleeTypes->baseFlags() != 0)
|
||||
|
@ -54,7 +54,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;
|
||||
@ -92,7 +92,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(cx->compartment()->activeAnalysis);
|
||||
JS_ASSERT(!ranBytecode());
|
||||
LifoAlloc &alloc = cx->analysisLifoAlloc();
|
||||
LifoAlloc &alloc = cx->typeLifoAlloc();
|
||||
|
||||
numSlots = TotalSlots(script_);
|
||||
|
||||
@ -557,7 +557,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx)
|
||||
return;
|
||||
}
|
||||
|
||||
LifoAlloc &alloc = cx->analysisLifoAlloc();
|
||||
LifoAlloc &alloc = cx->typeLifoAlloc();
|
||||
|
||||
lifetimes = alloc.newArray<LifetimeVariable>(numSlots);
|
||||
if (!lifetimes) {
|
||||
@ -812,7 +812,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;
|
||||
@ -827,7 +827,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;
|
||||
@ -858,7 +858,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;
|
||||
@ -947,7 +947,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;
|
||||
@ -1008,7 +1008,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
return;
|
||||
}
|
||||
|
||||
LifoAlloc &alloc = cx->analysisLifoAlloc();
|
||||
LifoAlloc &alloc = cx->typeLifoAlloc();
|
||||
unsigned maxDepth = script_->nslots - script_->nfixed;
|
||||
|
||||
/*
|
||||
@ -1403,8 +1403,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;
|
||||
@ -1436,7 +1436,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;
|
||||
@ -1455,7 +1455,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;
|
||||
@ -1655,7 +1655,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;
|
||||
|
@ -225,17 +225,14 @@ FollowBranch(JSContext *cx, JSScript *script, unsigned offset)
|
||||
}
|
||||
|
||||
/* Common representation of slots throughout analyses and the compiler. */
|
||||
static inline uint32_t CalleeSlot() {
|
||||
static inline uint32_t ThisSlot() {
|
||||
return 0;
|
||||
}
|
||||
static inline uint32_t ThisSlot() {
|
||||
return 1;
|
||||
}
|
||||
static inline uint32_t ArgSlot(uint32_t arg) {
|
||||
return 2 + arg;
|
||||
return 1 + arg;
|
||||
}
|
||||
static inline uint32_t LocalSlot(JSScript *script, uint32_t local) {
|
||||
return 2 + (script->function() ? script->function()->nargs : 0) + local;
|
||||
return 1 + (script->function() ? script->function()->nargs : 0) + local;
|
||||
}
|
||||
static inline uint32_t TotalSlots(JSScript *script) {
|
||||
return LocalSlot(script, 0) + script->nfixed;
|
||||
@ -622,8 +619,6 @@ class ScriptAnalysis
|
||||
|
||||
bool *escapedSlots;
|
||||
|
||||
types::StackTypeSet *undefinedTypeSet;
|
||||
|
||||
/* Which analyses have been performed. */
|
||||
bool ranBytecode_;
|
||||
bool ranSSA_;
|
||||
@ -829,18 +824,6 @@ class ScriptAnalysis
|
||||
const Vector<uint32_t> &exceptionTargets);
|
||||
void freezeNewValues(JSContext *cx, uint32_t offset);
|
||||
|
||||
struct TypeInferenceState {
|
||||
Vector<SSAPhiNode *> phiNodes;
|
||||
bool hasHole;
|
||||
types::StackTypeSet *forTypes;
|
||||
bool hasPropertyReadTypes;
|
||||
uint32_t propertyReadIndex;
|
||||
TypeInferenceState(JSContext *cx)
|
||||
: phiNodes(cx), hasHole(false), forTypes(NULL),
|
||||
hasPropertyReadTypes(false), propertyReadIndex(0)
|
||||
{}
|
||||
};
|
||||
|
||||
typedef Vector<SSAValue, 16> SeenVector;
|
||||
bool needsArgsObj(JSContext *cx, SeenVector &seen, const SSAValue &v);
|
||||
bool needsArgsObj(JSContext *cx, SeenVector &seen, SSAUseChain *use);
|
||||
|
@ -496,7 +496,6 @@ struct JSContext : public js::ExclusiveContext,
|
||||
bool hasWErrorOption() const { return hasOption(JSOPTION_WERROR); }
|
||||
|
||||
js::LifoAlloc &tempLifoAlloc() { return runtime()->tempLifoAlloc; }
|
||||
inline js::LifoAlloc &analysisLifoAlloc();
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
unsigned outstandingRequests;/* number of JS_BeginRequest calls
|
||||
|
@ -420,12 +420,6 @@ ExclusiveContext::typeLifoAlloc()
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
inline js::LifoAlloc &
|
||||
JSContext::analysisLifoAlloc()
|
||||
{
|
||||
return compartment()->analysisLifoAlloc;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSContext::setPendingException(js::Value v) {
|
||||
JS_ASSERT(!IsPoisonedValue(v));
|
||||
|
@ -47,7 +47,6 @@ JSCompartment::JSCompartment(Zone *zone, const JS::CompartmentOptions &options =
|
||||
global_(NULL),
|
||||
enterCompartmentDepth(0),
|
||||
lastCodeRelease(0),
|
||||
analysisLifoAlloc(ANALYSIS_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
|
||||
data(NULL),
|
||||
objectMetadataCallback(NULL),
|
||||
lastAnimationTime(0),
|
||||
@ -539,14 +538,11 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
|
||||
WeakMapBase::sweepCompartment(this);
|
||||
}
|
||||
|
||||
if (!zone()->isPreservingCode()) {
|
||||
JS_ASSERT(!types.constrainedOutputs);
|
||||
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DISCARD_ANALYSIS);
|
||||
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_FREE_TI_ARENA);
|
||||
rt->freeLifoAlloc.transferFrom(&analysisLifoAlloc);
|
||||
} else {
|
||||
if (zone()->isPreservingCode()) {
|
||||
gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_DISCARD_ANALYSIS);
|
||||
types.sweepShapes(fop);
|
||||
} else {
|
||||
JS_ASSERT(!types.constrainedOutputs);
|
||||
}
|
||||
|
||||
NativeIterator *ni = enumerators->next();
|
||||
@ -610,7 +606,6 @@ JSCompartment::clearTables()
|
||||
#endif
|
||||
JS_ASSERT(!debugScopes);
|
||||
JS_ASSERT(!gcWeakMapList);
|
||||
JS_ASSERT(!analysisLifoAlloc.used());
|
||||
JS_ASSERT(enumerators->next() == enumerators);
|
||||
|
||||
if (baseShapes.initialized())
|
||||
|
@ -185,11 +185,6 @@ struct JSCompartment
|
||||
|
||||
|
||||
int64_t lastCodeRelease;
|
||||
|
||||
/* Pools for analysis and type information in this compartment. */
|
||||
static const size_t ANALYSIS_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 32 * 1024;
|
||||
js::LifoAlloc analysisLifoAlloc;
|
||||
|
||||
bool activeAnalysis;
|
||||
|
||||
/* Type information about the scripts and objects in this compartment. */
|
||||
|
@ -314,8 +314,7 @@ types::TypeFailure(JSContext *cx, const char *fmt, ...)
|
||||
// TypeSet
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
TypeSet::TypeSet(Type type)
|
||||
: flags(0), objectSet(NULL), constraintList(NULL)
|
||||
TemporaryTypeSet::TemporaryTypeSet(Type type)
|
||||
{
|
||||
if (type.isUnknown()) {
|
||||
flags |= TYPE_FLAG_BASE_MASK;
|
||||
@ -398,9 +397,11 @@ TypeSet::addTypesToConstraint(JSContext *cx, TypeConstraint *constraint)
|
||||
constraint->newType(cx, this, types[i]);
|
||||
}
|
||||
|
||||
inline void
|
||||
void
|
||||
TypeSet::add(JSContext *cx, TypeConstraint *constraint, bool callExisting)
|
||||
{
|
||||
JS_ASSERT(isStackSet() || isHeapSet());
|
||||
|
||||
if (!constraint) {
|
||||
/* OOM failure while constructing the constraint. */
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
@ -471,35 +472,12 @@ TypeSet::print()
|
||||
}
|
||||
}
|
||||
|
||||
StackTypeSet *
|
||||
StackTypeSet::make(JSContext *cx, const char *name)
|
||||
{
|
||||
JS_ASSERT(cx->compartment()->activeAnalysis);
|
||||
|
||||
StackTypeSet *res = cx->analysisLifoAlloc().new_<StackTypeSet>();
|
||||
if (!res) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InferSpew(ISpewOps, "typeSet: %sT%p%s intermediate %s",
|
||||
InferSpewColor(res), res, InferSpewColorReset(),
|
||||
name);
|
||||
res->setPurged();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
StackTypeSet *
|
||||
TemporaryTypeSet *
|
||||
TypeSet::clone(LifoAlloc *alloc) const
|
||||
{
|
||||
unsigned objectCount = baseObjectCount();
|
||||
unsigned capacity = (objectCount >= 2) ? HashSetCapacity(objectCount) : 0;
|
||||
|
||||
StackTypeSet *res = alloc->new_<StackTypeSet>();
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
TypeObjectKey **newSet;
|
||||
if (capacity) {
|
||||
newSet = alloc->newArray<TypeObjectKey*>(capacity);
|
||||
@ -508,17 +486,17 @@ TypeSet::clone(LifoAlloc *alloc) const
|
||||
PodCopy(newSet, objectSet, capacity);
|
||||
}
|
||||
|
||||
res->flags = this->flags;
|
||||
res->objectSet = capacity ? newSet : this->objectSet;
|
||||
uint32_t newFlags = flags & ~(TYPE_FLAG_STACK_SET | TYPE_FLAG_HEAP_SET);
|
||||
TemporaryTypeSet *res = alloc->new_<TemporaryTypeSet>(newFlags, capacity ? newSet : objectSet);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool
|
||||
TypeSet::addObject(TypeObjectKey *key, LifoAlloc *alloc)
|
||||
TemporaryTypeSet::addObject(TypeObjectKey *key, LifoAlloc *alloc)
|
||||
{
|
||||
JS_ASSERT(!constraintList);
|
||||
|
||||
uint32_t objectCount = baseObjectCount();
|
||||
TypeObjectKey **pentry = HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
|
||||
(*alloc, objectSet, objectCount, key);
|
||||
@ -538,15 +516,14 @@ TypeSet::addObject(TypeObjectKey *key, LifoAlloc *alloc)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ StackTypeSet *
|
||||
/* static */ TemporaryTypeSet *
|
||||
TypeSet::unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc)
|
||||
{
|
||||
StackTypeSet *res = alloc->new_<StackTypeSet>();
|
||||
TemporaryTypeSet *res = alloc->new_<TemporaryTypeSet>(a->baseFlags() | b->baseFlags(),
|
||||
static_cast<TypeObjectKey**>(NULL));
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
res->flags = a->baseFlags() | b->baseFlags();
|
||||
|
||||
if (!res->unknownObject()) {
|
||||
for (size_t i = 0; i < a->getObjectCount() && !res->unknownObject(); i++) {
|
||||
TypeObjectKey *key = a->getObject(i);
|
||||
@ -595,13 +572,12 @@ class TypeConstraintSubset : public TypeConstraint
|
||||
void
|
||||
StackTypeSet::addSubset(JSContext *cx, StackTypeSet *target)
|
||||
{
|
||||
add(cx, cx->analysisLifoAlloc().new_<TypeConstraintSubset>(target));
|
||||
add(cx, cx->typeLifoAlloc().new_<TypeConstraintSubset>(target));
|
||||
}
|
||||
|
||||
void
|
||||
HeapTypeSet::addSubset(JSContext *cx, HeapTypeSet *target)
|
||||
{
|
||||
JS_ASSERT(!target->purged());
|
||||
add(cx, cx->typeLifoAlloc().new_<TypeConstraintSubset>(target));
|
||||
}
|
||||
|
||||
@ -671,7 +647,7 @@ GetValueTypeFromTypeFlags(TypeFlags flags)
|
||||
}
|
||||
|
||||
JSValueType
|
||||
StackTypeSet::getKnownTypeTag()
|
||||
TemporaryTypeSet::getKnownTypeTag()
|
||||
{
|
||||
TypeFlags flags = baseFlags();
|
||||
JSValueType type;
|
||||
@ -722,7 +698,7 @@ HeapTypeSet::getKnownTypeTag(JSContext *cx)
|
||||
}
|
||||
|
||||
bool
|
||||
StackTypeSet::mightBeType(JSValueType type)
|
||||
TemporaryTypeSet::mightBeType(JSValueType type)
|
||||
{
|
||||
if (unknown())
|
||||
return true;
|
||||
@ -768,7 +744,7 @@ class TypeConstraintFreezeObjectFlags : public TypeConstraint
|
||||
} /* anonymous namespace */
|
||||
|
||||
bool
|
||||
StackTypeSet::hasObjectFlags(JSContext *cx, TypeObjectFlags flags)
|
||||
TemporaryTypeSet::hasObjectFlags(JSContext *cx, TypeObjectFlags flags)
|
||||
{
|
||||
if (unknownObject())
|
||||
return true;
|
||||
@ -797,7 +773,7 @@ StackTypeSet::hasObjectFlags(JSContext *cx, TypeObjectFlags flags)
|
||||
* Add a constraint on the the object to pick up changes in the
|
||||
* object's properties.
|
||||
*/
|
||||
TypeSet *types = object->getProperty(cx, JSID_EMPTY, false);
|
||||
HeapTypeSet *types = object->getProperty(cx, JSID_EMPTY, false);
|
||||
if (!types)
|
||||
return true;
|
||||
types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeObjectFlags>(
|
||||
@ -940,7 +916,7 @@ HeapTypeSet::knownNonEmpty(JSContext *cx)
|
||||
}
|
||||
|
||||
bool
|
||||
StackTypeSet::filtersType(const StackTypeSet *other, Type filteredType) const
|
||||
TemporaryTypeSet::filtersType(const TemporaryTypeSet *other, Type filteredType) const
|
||||
{
|
||||
if (other->unknown())
|
||||
return unknown();
|
||||
@ -966,8 +942,8 @@ StackTypeSet::filtersType(const StackTypeSet *other, Type filteredType) const
|
||||
return true;
|
||||
}
|
||||
|
||||
StackTypeSet::DoubleConversion
|
||||
StackTypeSet::convertDoubleElements(JSContext *cx)
|
||||
TemporaryTypeSet::DoubleConversion
|
||||
TemporaryTypeSet::convertDoubleElements(JSContext *cx)
|
||||
{
|
||||
if (unknownObject() || !getObjectCount())
|
||||
return AmbiguousDoubleConversion;
|
||||
@ -1033,10 +1009,8 @@ StackTypeSet::convertDoubleElements(JSContext *cx)
|
||||
}
|
||||
|
||||
bool
|
||||
HeapTypeSet::knownSubset(JSContext *cx, TypeSet *other)
|
||||
HeapTypeSet::knownSubset(JSContext *cx, HeapTypeSet *other)
|
||||
{
|
||||
JS_ASSERT(!other->constraintsPurged());
|
||||
|
||||
if (!isSubset(other))
|
||||
return false;
|
||||
|
||||
@ -1046,7 +1020,7 @@ HeapTypeSet::knownSubset(JSContext *cx, TypeSet *other)
|
||||
}
|
||||
|
||||
const Class *
|
||||
StackTypeSet::getKnownClass()
|
||||
TemporaryTypeSet::getKnownClass()
|
||||
{
|
||||
if (unknownObject())
|
||||
return NULL;
|
||||
@ -1072,7 +1046,7 @@ StackTypeSet::getKnownClass()
|
||||
}
|
||||
|
||||
int
|
||||
StackTypeSet::getTypedArrayType()
|
||||
TemporaryTypeSet::getTypedArrayType()
|
||||
{
|
||||
const Class *clasp = getKnownClass();
|
||||
|
||||
@ -1082,7 +1056,7 @@ StackTypeSet::getTypedArrayType()
|
||||
}
|
||||
|
||||
bool
|
||||
StackTypeSet::isDOMClass()
|
||||
TemporaryTypeSet::isDOMClass()
|
||||
{
|
||||
if (unknownObject())
|
||||
return false;
|
||||
@ -1105,7 +1079,7 @@ StackTypeSet::isDOMClass()
|
||||
}
|
||||
|
||||
bool
|
||||
StackTypeSet::maybeCallable()
|
||||
TemporaryTypeSet::maybeCallable()
|
||||
{
|
||||
if (!maybeObject())
|
||||
return false;
|
||||
@ -1131,7 +1105,7 @@ StackTypeSet::maybeCallable()
|
||||
}
|
||||
|
||||
JSObject *
|
||||
StackTypeSet::getCommonPrototype()
|
||||
TemporaryTypeSet::getCommonPrototype()
|
||||
{
|
||||
if (unknownObject())
|
||||
return NULL;
|
||||
@ -1162,7 +1136,7 @@ StackTypeSet::getCommonPrototype()
|
||||
}
|
||||
|
||||
JSObject *
|
||||
StackTypeSet::getSingleton()
|
||||
TemporaryTypeSet::getSingleton()
|
||||
{
|
||||
if (baseFlags() != 0 || baseObjectCount() != 1)
|
||||
return NULL;
|
||||
@ -1196,7 +1170,7 @@ HeapTypeSet::needsBarrier(JSContext *cx)
|
||||
}
|
||||
|
||||
bool
|
||||
StackTypeSet::propertyNeedsBarrier(JSContext *cx, jsid id)
|
||||
TemporaryTypeSet::propertyNeedsBarrier(JSContext *cx, jsid id)
|
||||
{
|
||||
RootedId typeId(cx, IdToTypeId(id));
|
||||
|
||||
@ -1576,7 +1550,7 @@ types::ArrayPrototypeHasIndexedProperty(JSContext *cx, HandleScript script)
|
||||
}
|
||||
|
||||
bool
|
||||
types::TypeCanHaveExtraIndexedProperties(JSContext *cx, StackTypeSet *types)
|
||||
types::TypeCanHaveExtraIndexedProperties(JSContext *cx, TemporaryTypeSet *types)
|
||||
{
|
||||
const Class *clasp = types->getKnownClass();
|
||||
|
||||
@ -2894,7 +2868,7 @@ types::AddClearDefiniteFunctionUsesInScript(JSContext *cx, TypeObject *type,
|
||||
// This is a type set that might have been used when inlining
|
||||
// |calleeScript| into |script|.
|
||||
types->add(cx,
|
||||
cx->analysisLifoAlloc().new_<TypeConstraintClearDefiniteSingle>(type));
|
||||
cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteSingle>(type));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3327,13 +3301,9 @@ JSScript::makeTypes(JSContext *cx)
|
||||
new(types) TypeScript();
|
||||
|
||||
TypeSet *typeArray = types->typeArray();
|
||||
TypeSet *returnTypes = TypeScript::ReturnTypes(this);
|
||||
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
TypeSet *types = &typeArray[i];
|
||||
if (types != returnTypes)
|
||||
types->setConstraintsPurged();
|
||||
}
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
new (&typeArray[i]) StackTypeSet();
|
||||
|
||||
if (isCallsiteClone) {
|
||||
/*
|
||||
@ -3348,7 +3318,6 @@ JSScript::makeTypes(JSContext *cx)
|
||||
if (!original->ensureHasTypes(cx))
|
||||
return false;
|
||||
|
||||
TypeScript::ReturnTypes(this)->addSubset(cx, TypeScript::ReturnTypes(original));
|
||||
TypeScript::ThisTypes(this)->addSubset(cx, TypeScript::ThisTypes(original));
|
||||
for (unsigned i = 0; i < function()->nargs; i++)
|
||||
TypeScript::ArgTypes(this, i)->addSubset(cx, TypeScript::ArgTypes(original, i));
|
||||
@ -3359,9 +3328,6 @@ JSScript::makeTypes(JSContext *cx)
|
||||
InferSpew(ISpewOps, "typeSet: %sT%p%s bytecode%u #%u",
|
||||
InferSpewColor(&typeArray[i]), &typeArray[i], InferSpewColorReset(),
|
||||
i, id());
|
||||
InferSpew(ISpewOps, "typeSet: %sT%p%s return #%u",
|
||||
InferSpewColor(returnTypes), returnTypes, InferSpewColorReset(),
|
||||
id());
|
||||
TypeSet *thisTypes = TypeScript::ThisTypes(this);
|
||||
InferSpew(ISpewOps, "typeSet: %sT%p%s this #%u",
|
||||
InferSpewColor(thisTypes), thisTypes, InferSpewColorReset(),
|
||||
@ -3384,7 +3350,7 @@ JSScript::makeBytecodeTypeMap(JSContext *cx)
|
||||
JS_ASSERT(cx->typeInferenceEnabled());
|
||||
JS_ASSERT(types && !types->bytecodeMap);
|
||||
|
||||
types->bytecodeMap = cx->analysisLifoAlloc().newArrayUninitialized<uint32_t>(nTypeSets + 1);
|
||||
types->bytecodeMap = cx->typeLifoAlloc().newArrayUninitialized<uint32_t>(nTypeSets + 1);
|
||||
|
||||
if (!types->bytecodeMap)
|
||||
return false;
|
||||
@ -3415,7 +3381,7 @@ JSScript::makeAnalysis(JSContext *cx)
|
||||
|
||||
AutoEnterAnalysis enter(cx);
|
||||
|
||||
types->analysis = cx->analysisLifoAlloc().new_<ScriptAnalysis>(this);
|
||||
types->analysis = cx->typeLifoAlloc().new_<ScriptAnalysis>(this);
|
||||
|
||||
if (!types->analysis)
|
||||
return false;
|
||||
@ -3789,8 +3755,6 @@ ExclusiveContext::getLazyType(const Class *clasp, TaggedProto proto)
|
||||
void
|
||||
TypeSet::sweep(Zone *zone)
|
||||
{
|
||||
JS_ASSERT(!purged());
|
||||
|
||||
/*
|
||||
* Purge references to type objects that are no longer live. Type sets hold
|
||||
* only weak references. For type sets containing more than one object,
|
||||
@ -4184,15 +4148,12 @@ TypeScript::AddFreezeConstraints(JSContext *cx, JSScript *script)
|
||||
*/
|
||||
|
||||
size_t count = TypeScript::NumTypeSets(script);
|
||||
TypeSet *returnTypes = TypeScript::ReturnTypes(script);
|
||||
|
||||
TypeSet *array = script->types->typeArray();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
TypeSet *types = &array[i];
|
||||
if (types == returnTypes)
|
||||
continue;
|
||||
JS_ASSERT(types->constraintsPurged());
|
||||
types->add(cx, cx->analysisLifoAlloc().new_<TypeConstraintFreezeStack>(script), false);
|
||||
JS_ASSERT(types->isStackSet());
|
||||
types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeStack>(script), false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4228,8 +4189,6 @@ Zone::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, size_t *typePool)
|
||||
void
|
||||
JSCompartment::sizeOfTypeInferenceData(JS::TypeInferenceSizes *sizes, mozilla::MallocSizeOf mallocSizeOf)
|
||||
{
|
||||
sizes->analysisPool += analysisLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
|
||||
|
||||
/* Pending arrays are cleared on GC along with the analysis pool. */
|
||||
sizes->pendingArrays += mallocSizeOf(types.pendingArray);
|
||||
|
||||
@ -4382,8 +4341,6 @@ TypeScript::printTypes(JSContext *cx, HandleScript script) const
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n return:");
|
||||
TypeScript::ReturnTypes(script)->print();
|
||||
fprintf(stderr, "\n this:");
|
||||
TypeScript::ThisTypes(script)->print();
|
||||
|
||||
|
298
js/src/jsinfer.h
298
js/src/jsinfer.h
@ -212,38 +212,31 @@ inline Type GetValueType(const Value &val);
|
||||
/*
|
||||
* Type inference memory management overview.
|
||||
*
|
||||
* 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.
|
||||
* Type information about the values observed within scripts and about the
|
||||
* contents of the heap is accumulated as the program executes. Compilation
|
||||
* accumulates constraints relating type information on the heap with the
|
||||
* compilations that should be invalidated when those types change. This data
|
||||
* is periodically cleared to reduce memory usage.
|
||||
*
|
||||
* There are two operations which can clear inference and analysis data.
|
||||
* 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.
|
||||
*
|
||||
* - Analysis purges clear analysis information while retaining jitcode.
|
||||
* The following data is cleared by all non-preserving GCs:
|
||||
*
|
||||
* - 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.
|
||||
* - The ScriptAnalysis for each analyzed script and data from each analysis
|
||||
* pass performed.
|
||||
*
|
||||
* There are several categories of data affected differently by the above
|
||||
* operations.
|
||||
* - Property type sets for singleton JS objects.
|
||||
*
|
||||
* - 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.
|
||||
* - Type constraints and dead references in all type sets.
|
||||
*
|
||||
* - 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.
|
||||
* The following data is occasionally cleared by non-preserving GCs:
|
||||
*
|
||||
* - 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.
|
||||
* - TypeScripts and their type sets are occasionally destroyed, per a timer.
|
||||
*
|
||||
* - When a JSScript or TypeObject is swept, type information for its contents
|
||||
* is destroyed.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -307,22 +300,24 @@ 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.
|
||||
* Flags describing the kind of type set this is.
|
||||
*
|
||||
* - StackTypeSet are associated with TypeScripts, for arguments and values
|
||||
* observed at property reads. These are implicitly frozen on compilation
|
||||
* and do not have constraints attached to them.
|
||||
*
|
||||
* - HeapTypeSet are associated with the properties of TypeObjects. These
|
||||
* may have constraints added to them to propagate types around or to
|
||||
* trigger invalidation of compiled code.
|
||||
*
|
||||
* - TemporaryTypeSet are created during compilation and do not outlive
|
||||
* that compilation.
|
||||
*/
|
||||
TYPE_FLAG_PURGED = 0x00020000,
|
||||
TYPE_FLAG_STACK_SET = 0x00020000,
|
||||
TYPE_FLAG_HEAP_SET = 0x00040000,
|
||||
|
||||
/*
|
||||
* 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. */
|
||||
/* Additional flags for HeapTypeSet sets. */
|
||||
|
||||
/*
|
||||
* Whether there are subset constraints propagating the possible types
|
||||
@ -430,10 +425,12 @@ typedef uint32_t TypeObjectFlags;
|
||||
|
||||
class StackTypeSet;
|
||||
class HeapTypeSet;
|
||||
class TemporaryTypeSet;
|
||||
|
||||
/* Information about the set of types associated with an lvalue. */
|
||||
class TypeSet
|
||||
{
|
||||
protected:
|
||||
/* Flags for this type set. */
|
||||
TypeFlags flags;
|
||||
|
||||
@ -446,11 +443,9 @@ class TypeSet
|
||||
TypeConstraint *constraintList;
|
||||
|
||||
TypeSet()
|
||||
: flags(0), objectSet(NULL), constraintList(NULL)
|
||||
: flags(0), objectSet(NULL), constraintList(NULL)
|
||||
{}
|
||||
|
||||
TypeSet(Type type);
|
||||
|
||||
void print();
|
||||
|
||||
inline void sweep(JS::Zone *zone);
|
||||
@ -479,14 +474,8 @@ class TypeSet
|
||||
return flags >> TYPE_FLAG_DEFINITE_SHIFT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clone a type set into an arbitrary allocator. The result should not be
|
||||
* modified further.
|
||||
*/
|
||||
StackTypeSet *clone(LifoAlloc *alloc) const;
|
||||
|
||||
/* Join two type sets into a new set. The result should not be modified further. */
|
||||
static StackTypeSet *unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc);
|
||||
static TemporaryTypeSet *unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc);
|
||||
|
||||
/*
|
||||
* Add a type to this set, calling any constraint handlers if this is a new
|
||||
@ -497,12 +486,6 @@ class TypeSet
|
||||
/* Mark this type set as representing an own property or configured property. */
|
||||
inline void setOwnProperty(ExclusiveContext *cx, bool configured);
|
||||
|
||||
/*
|
||||
* Add an object to this set using the specified allocator, without
|
||||
* triggering constraints.
|
||||
*/
|
||||
bool addObject(TypeObjectKey *key, LifoAlloc *alloc);
|
||||
|
||||
/*
|
||||
* Iterate through the objects in this set. getObjectCount overapproximates
|
||||
* in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject
|
||||
@ -527,11 +510,12 @@ 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; }
|
||||
|
||||
bool purged() { return !!(flags & TYPE_FLAG_PURGED); }
|
||||
void setPurged() { flags |= TYPE_FLAG_PURGED | TYPE_FLAG_CONSTRAINTS_PURGED; }
|
||||
bool isStackSet() {
|
||||
return flags & TYPE_FLAG_STACK_SET;
|
||||
}
|
||||
bool isHeapSet() {
|
||||
return flags & TYPE_FLAG_HEAP_SET;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get whether this type set is known to be a subset of other.
|
||||
@ -539,11 +523,20 @@ class TypeSet
|
||||
*/
|
||||
bool isSubset(TypeSet *other);
|
||||
|
||||
inline StackTypeSet *toStackTypeSet();
|
||||
inline HeapTypeSet *toHeapTypeSet();
|
||||
/* Forward all types in this set to the specified constraint. */
|
||||
void addTypesToConstraint(JSContext *cx, TypeConstraint *constraint);
|
||||
|
||||
inline void addTypesToConstraint(JSContext *cx, TypeConstraint *constraint);
|
||||
inline void add(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
|
||||
/* Add a new constraint to this set. */
|
||||
void add(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
|
||||
|
||||
inline StackTypeSet *toStackSet();
|
||||
inline HeapTypeSet *toHeapSet();
|
||||
|
||||
/*
|
||||
* Clone a type set into an arbitrary allocator. The result should not be
|
||||
* modified further.
|
||||
*/
|
||||
TemporaryTypeSet *clone(LifoAlloc *alloc) const;
|
||||
|
||||
protected:
|
||||
uint32_t baseObjectCount() const {
|
||||
@ -554,28 +547,78 @@ class TypeSet
|
||||
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:
|
||||
|
||||
StackTypeSet() : TypeSet() {}
|
||||
StackTypeSet(Type type) : TypeSet(type) {}
|
||||
|
||||
/*
|
||||
* Make a type set with the specified debugging name, not embedded in
|
||||
* another structure.
|
||||
*/
|
||||
static StackTypeSet *make(JSContext *cx, const char *name);
|
||||
StackTypeSet() { flags |= TYPE_FLAG_STACK_SET; }
|
||||
|
||||
/* Propagate any types from this set into target. */
|
||||
void addSubset(JSContext *cx, StackTypeSet *target);
|
||||
};
|
||||
|
||||
class HeapTypeSet : public TypeSet
|
||||
{
|
||||
public:
|
||||
HeapTypeSet() { flags |= TYPE_FLAG_HEAP_SET; }
|
||||
|
||||
/* Propagate any types from this set into target. */
|
||||
void addSubset(JSContext *cx, HeapTypeSet *target);
|
||||
|
||||
/* Completely freeze the contents of this type set. */
|
||||
void addFreeze(JSContext *cx);
|
||||
|
||||
/*
|
||||
* Watch for a generic object state change on a type object. This currently
|
||||
* includes reallocations of slot pointers for global objects, and changes
|
||||
* to newScript data on types.
|
||||
*/
|
||||
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
|
||||
* has additionally been reconfigured as non-configurable, non-enumerable
|
||||
* or non-writable (this only applies to properties that have changed after
|
||||
* having been created, not to e.g. properties non-writable on creation).
|
||||
*/
|
||||
bool isOwnProperty(JSContext *cx, TypeObject *object, bool configurable);
|
||||
|
||||
/* Get whether this type set is non-empty. */
|
||||
bool knownNonEmpty(JSContext *cx);
|
||||
|
||||
/* Get whether this type set is known to be a subset of other. */
|
||||
bool knownSubset(JSContext *cx, HeapTypeSet *other);
|
||||
|
||||
/* Get the single value which can appear in this type set, otherwise NULL. */
|
||||
JSObject *getSingleton(JSContext *cx);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/* Get any type tag which all values in this set must have. */
|
||||
JSValueType getKnownTypeTag(JSContext *cx);
|
||||
};
|
||||
|
||||
class TemporaryTypeSet : public TypeSet
|
||||
{
|
||||
public:
|
||||
TemporaryTypeSet() {}
|
||||
TemporaryTypeSet(Type type);
|
||||
|
||||
TemporaryTypeSet(uint32_t flags, TypeObjectKey **objectSet) {
|
||||
this->flags = flags;
|
||||
this->objectSet = objectSet;
|
||||
JS_ASSERT(!isStackSet() && !isHeapSet());
|
||||
}
|
||||
|
||||
/* Add an object to this set using the specified allocator. */
|
||||
bool addObject(TypeObjectKey *key, LifoAlloc *alloc);
|
||||
|
||||
/*
|
||||
* Constraints for JIT compilation.
|
||||
@ -638,7 +681,7 @@ class StackTypeSet : public TypeSet
|
||||
* Whether this set contains all types in other, except (possibly) the
|
||||
* specified type.
|
||||
*/
|
||||
bool filtersType(const StackTypeSet *other, Type type) const;
|
||||
bool filtersType(const TemporaryTypeSet *other, Type type) const;
|
||||
|
||||
enum DoubleConversion {
|
||||
/* All types in the set should use eager double conversion. */
|
||||
@ -661,71 +704,17 @@ class StackTypeSet : public TypeSet
|
||||
DoubleConversion convertDoubleElements(JSContext *cx);
|
||||
};
|
||||
|
||||
/*
|
||||
* 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:
|
||||
|
||||
/* Propagate any types from this set into target. */
|
||||
void addSubset(JSContext *cx, HeapTypeSet *target);
|
||||
|
||||
/* Completely freeze the contents of this type set. */
|
||||
void addFreeze(JSContext *cx);
|
||||
|
||||
/*
|
||||
* Watch for a generic object state change on a type object. This currently
|
||||
* includes reallocations of slot pointers for global objects, and changes
|
||||
* to newScript data on types.
|
||||
*/
|
||||
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
|
||||
* has additionally been reconfigured as non-configurable, non-enumerable
|
||||
* or non-writable (this only applies to properties that have changed after
|
||||
* having been created, not to e.g. properties non-writable on creation).
|
||||
*/
|
||||
bool isOwnProperty(JSContext *cx, TypeObject *object, bool configurable);
|
||||
|
||||
/* Get whether this type set is non-empty. */
|
||||
bool knownNonEmpty(JSContext *cx);
|
||||
|
||||
/* Get whether this type set is known to be a subset of other. */
|
||||
bool knownSubset(JSContext *cx, TypeSet *other);
|
||||
|
||||
/* Get the single value which can appear in this type set, otherwise NULL. */
|
||||
JSObject *getSingleton(JSContext *cx);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/* Get any type tag which all values in this set must have. */
|
||||
JSValueType getKnownTypeTag(JSContext *cx);
|
||||
};
|
||||
|
||||
inline StackTypeSet *
|
||||
TypeSet::toStackTypeSet()
|
||||
TypeSet::toStackSet()
|
||||
{
|
||||
JS_ASSERT(constraintsPurged());
|
||||
JS_ASSERT(isStackSet());
|
||||
return (StackTypeSet *) this;
|
||||
}
|
||||
|
||||
inline HeapTypeSet *
|
||||
TypeSet::toHeapTypeSet()
|
||||
TypeSet::toHeapSet()
|
||||
{
|
||||
JS_ASSERT(!constraintsPurged());
|
||||
JS_ASSERT(isHeapSet());
|
||||
return (HeapTypeSet *) this;
|
||||
}
|
||||
|
||||
@ -1236,34 +1225,7 @@ ArrayPrototypeHasIndexedProperty(JSContext *cx, HandleScript script);
|
||||
|
||||
/* Whether obj or any of its prototypes have an indexed property. */
|
||||
bool
|
||||
TypeCanHaveExtraIndexedProperties(JSContext *cx, StackTypeSet *types);
|
||||
|
||||
/*
|
||||
* Type information about a callsite. this is separated from the bytecode
|
||||
* information itself so we can handle higher order functions not called
|
||||
* directly via a bytecode.
|
||||
*/
|
||||
struct TypeCallsite
|
||||
{
|
||||
JSScript *script;
|
||||
jsbytecode *pc;
|
||||
|
||||
/* Whether this is a 'NEW' call. */
|
||||
bool isNew;
|
||||
|
||||
/* Types of each argument to the call. */
|
||||
unsigned argumentCount;
|
||||
StackTypeSet **argumentTypes;
|
||||
|
||||
/* Types of the this variable. */
|
||||
StackTypeSet *thisTypes;
|
||||
|
||||
/* Type set receiving the return value of this call. */
|
||||
StackTypeSet *returnTypes;
|
||||
|
||||
inline TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
bool isNew, unsigned argumentCount);
|
||||
};
|
||||
TypeCanHaveExtraIndexedProperties(JSContext *cx, TemporaryTypeSet *types);
|
||||
|
||||
/* Persistent type information for a script, retained across GCs. */
|
||||
class TypeScript
|
||||
@ -1295,13 +1257,9 @@ class 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);
|
||||
|
||||
/* Follows slot layout in jsanalyze.h, can get this/arg/local type sets. */
|
||||
static inline StackTypeSet *SlotTypes(JSScript *script, unsigned slot);
|
||||
|
||||
/* Get the type set for values observed at an opcode. */
|
||||
static inline StackTypeSet *BytecodeTypes(JSScript *script, jsbytecode *pc);
|
||||
|
||||
|
@ -676,18 +676,11 @@ TypeScript::NumTypeSets(JSScript *script)
|
||||
return script->nTypeSets + analyze::LocalSlot(script, 0);
|
||||
}
|
||||
|
||||
/* static */ inline HeapTypeSet *
|
||||
TypeScript::ReturnTypes(JSScript *script)
|
||||
{
|
||||
TypeSet *types = script->types->typeArray() + script->nTypeSets + js::analyze::CalleeSlot();
|
||||
return types->toHeapTypeSet();
|
||||
}
|
||||
|
||||
/* static */ inline StackTypeSet *
|
||||
TypeScript::ThisTypes(JSScript *script)
|
||||
{
|
||||
TypeSet *types = script->types->typeArray() + script->nTypeSets + js::analyze::ThisSlot();
|
||||
return types->toStackTypeSet();
|
||||
return types->toStackSet();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -701,15 +694,7 @@ 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();
|
||||
}
|
||||
|
||||
/* static */ inline StackTypeSet *
|
||||
TypeScript::SlotTypes(JSScript *script, unsigned slot)
|
||||
{
|
||||
JS_ASSERT(slot < js::analyze::LocalSlot(script, 0));
|
||||
TypeSet *types = script->types->typeArray() + script->nTypeSets + slot;
|
||||
return types->toStackTypeSet();
|
||||
return types->toStackSet();
|
||||
}
|
||||
|
||||
/* static */ inline StackTypeSet *
|
||||
@ -725,12 +710,12 @@ TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc)
|
||||
// See if this pc is the next typeset opcode after the last one looked up.
|
||||
if (bytecodeMap[*hint + 1] == offset && (*hint + 1) < script->nTypeSets) {
|
||||
(*hint)++;
|
||||
return script->types->typeArray()->toStackTypeSet() + *hint;
|
||||
return script->types->typeArray()->toStackSet() + *hint;
|
||||
}
|
||||
|
||||
// See if this pc is the same as the last one looked up.
|
||||
if (bytecodeMap[*hint] == offset)
|
||||
return script->types->typeArray()->toStackTypeSet() + *hint;
|
||||
return script->types->typeArray()->toStackSet() + *hint;
|
||||
|
||||
// Fall back to a binary search.
|
||||
size_t bottom = 0;
|
||||
@ -752,7 +737,7 @@ TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc)
|
||||
JS_ASSERT(bytecodeMap[mid] == offset || mid == top);
|
||||
|
||||
*hint = mid;
|
||||
return script->types->typeArray()->toStackTypeSet() + *hint;
|
||||
return script->types->typeArray()->toStackSet() + *hint;
|
||||
}
|
||||
|
||||
/* static */ inline TypeObject *
|
||||
@ -1275,6 +1260,10 @@ TypeSet::addType(ExclusiveContext *cxArg, Type type)
|
||||
{
|
||||
JS_ASSERT(cxArg->compartment()->activeAnalysis);
|
||||
|
||||
// Temporary type sets use a separate LifoAlloc for storage.
|
||||
JS_ASSERT_IF(!type.isUnknown() && !type.isAnyObject() && type.isObject(),
|
||||
isStackSet() || isHeapSet());
|
||||
|
||||
if (unknown())
|
||||
return;
|
||||
|
||||
@ -1298,13 +1287,10 @@ TypeSet::addType(ExclusiveContext *cxArg, Type type)
|
||||
if (type.isAnyObject())
|
||||
goto unknownObject;
|
||||
|
||||
LifoAlloc &alloc =
|
||||
purged() ? cxArg->compartment()->analysisLifoAlloc : cxArg->typeLifoAlloc();
|
||||
|
||||
uint32_t objectCount = baseObjectCount();
|
||||
TypeObjectKey *object = type.objectKey();
|
||||
TypeObjectKey **pentry = HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
|
||||
(alloc, objectSet, objectCount, object);
|
||||
(cxArg->typeLifoAlloc(), objectSet, objectCount, object);
|
||||
if (!pentry) {
|
||||
cxArg->compartment()->types.setPendingNukeTypes(cxArg);
|
||||
return;
|
||||
@ -1431,20 +1417,6 @@ TypeSet::getTypeOrSingleObject(JSContext *cx, unsigned i, TypeObject **result) c
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// TypeCallsite
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline
|
||||
TypeCallsite::TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
bool isNew, unsigned argumentCount)
|
||||
: script(script), pc(pc), isNew(isNew), argumentCount(argumentCount),
|
||||
thisTypes(NULL), returnTypes(NULL)
|
||||
{
|
||||
/* Caller must check for failure. */
|
||||
argumentTypes = cx->analysisLifoAlloc().newArray<StackTypeSet*>(argumentCount);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// TypeObject
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
@ -2159,11 +2159,6 @@ ReportCompartmentStats(const JS::CompartmentStats &cStats,
|
||||
cStats.typeInference.typeResults,
|
||||
"Memory used by dynamic type results produced by scripts.");
|
||||
|
||||
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("type-inference/analysis-pool"),
|
||||
cStats.typeInference.analysisPool,
|
||||
"Memory holding transient analysis information used during type inference and "
|
||||
"compilation.");
|
||||
|
||||
ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("type-inference/pending-arrays"),
|
||||
cStats.typeInference.pendingArrays,
|
||||
"Memory used for solving constraints during type inference.");
|
||||
|
Loading…
x
Reference in New Issue
Block a user