Bug 915473 - Distinguish stack type sets from compiler-created temporary type sets, r=jandem.

This commit is contained in:
Brian Hackett 2013-09-12 18:30:03 -06:00
parent 705a73caba
commit 602e976657
20 changed files with 412 additions and 554 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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 {

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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));

View File

@ -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())

View File

@ -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. */

View File

@ -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();

View File

@ -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);

View File

@ -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
/////////////////////////////////////////////////////////////////////

View File

@ -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.");