Bug 924611 - Don't create lazy type objects and type properties in IonBuilder, r=jandem.

This commit is contained in:
Brian Hackett 2013-10-14 12:13:41 -06:00
parent 251cbba440
commit 724613f48e
12 changed files with 285 additions and 161 deletions

View File

@ -1368,9 +1368,6 @@ ICUpdatedStub::addUpdateStubForValue(JSContext *cx, HandleScript script, HandleO
return true; return true;
} }
if (!obj->getType(cx))
return false;
types::EnsureTrackPropertyTypes(cx, obj, id); types::EnsureTrackPropertyTypes(cx, obj, id);
if (val.isPrimitive()) { if (val.isPrimitive()) {
@ -5326,6 +5323,10 @@ TryAttachGlobalNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback *
RootedId id(cx, NameToId(name)); RootedId id(cx, NameToId(name));
// Instantiate this global property, for use during Ion compilation.
if (IsIonEnabled(cx))
types::EnsureTrackPropertyTypes(cx, global, NameToId(name));
// The property must be found, and it must be found as a normal data property. // The property must be found, and it must be found as a normal data property.
RootedShape shape(cx, global->nativeLookup(cx, id)); RootedShape shape(cx, global->nativeLookup(cx, id));
if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot()) if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot())
@ -5383,6 +5384,10 @@ TryAttachScopeNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback *s
if (!IsCacheableGetPropReadSlot(scopeChain, scopeChain, shape)) if (!IsCacheableGetPropReadSlot(scopeChain, scopeChain, shape))
return true; return true;
// Instantiate properties on singleton scope chain objects, for use during Ion compilation.
if (scopeChain->hasSingletonType() && IsIonEnabled(cx))
types::EnsureTrackPropertyTypes(cx, scopeChain, NameToId(name));
bool isFixedSlot; bool isFixedSlot;
uint32_t offset; uint32_t offset;
GetFixedOrDynamicSlotOffset(scopeChain, shape->slot(), &isFixedSlot, &offset); GetFixedOrDynamicSlotOffset(scopeChain, shape->slot(), &isFixedSlot, &offset);
@ -5810,6 +5815,10 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
uint32_t offset; uint32_t offset;
GetFixedOrDynamicSlotOffset(holder, shape->slot(), &isFixedSlot, &offset); GetFixedOrDynamicSlotOffset(holder, shape->slot(), &isFixedSlot, &offset);
// Instantiate this property for singleton holders, for use during Ion compilation.
if (IsIonEnabled(cx))
types::EnsureTrackPropertyTypes(cx, holder, NameToId(name));
ICStub::Kind kind = (obj == holder) ? ICStub::GetProp_Native ICStub::Kind kind = (obj == holder) ? ICStub::GetProp_Native
: ICStub::GetProp_NativePrototype; : ICStub::GetProp_NativePrototype;
@ -5919,6 +5928,10 @@ TryAttachStringGetPropStub(JSContext *cx, HandleScript script, ICGetProp_Fallbac
if (!stringProto) if (!stringProto)
return false; return false;
// Instantiate this property, for use during Ion compilation.
if (IsIonEnabled(cx))
types::EnsureTrackPropertyTypes(cx, stringProto, NameToId(name));
// For now, only look for properties directly set on String.prototype // For now, only look for properties directly set on String.prototype
RootedId propId(cx, NameToId(name)); RootedId propId(cx, NameToId(name));
RootedShape shape(cx, stringProto->nativeLookup(cx, propId)); RootedShape shape(cx, stringProto->nativeLookup(cx, propId));
@ -7465,6 +7478,11 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsb
return true; return true;
} }
// Keep track of the function's |prototype| property in type
// information, for use during Ion compilation.
if (IsIonEnabled(cx))
types::EnsureTrackPropertyTypes(cx, fun, NameToId(cx->names().prototype));
IonSpew(IonSpew_BaselineIC, IonSpew(IonSpew_BaselineIC,
" Generating Call_Scripted stub (fun=%p, %s:%d, cons=%s)", " Generating Call_Scripted stub (fun=%p, %s:%d, cons=%s)",
fun.get(), fun->nonLazyScript()->filename(), fun->nonLazyScript()->lineno, fun.get(), fun->nonLazyScript()->filename(), fun->nonLazyScript()->lineno,

View File

@ -2151,7 +2151,7 @@ CodeGenerator::visitApplyArgsGeneric(LApplyArgsGeneric *apply)
ExecutionMode executionMode = gen->info().executionMode(); ExecutionMode executionMode = gen->info().executionMode();
if (apply->hasSingleTarget()) { if (apply->hasSingleTarget()) {
JSFunction *target = apply->getSingleTarget(); JSFunction *target = apply->getSingleTarget();
if (!CanIonCompile(target, executionMode)) { if (target->isNative()) {
if (!emitCallInvokeFunction(apply, copyreg)) if (!emitCallInvokeFunction(apply, copyreg))
return false; return false;
emitPopArguments(apply, copyreg); emitPopArguments(apply, copyreg);

View File

@ -73,12 +73,6 @@ CanIonCompile(JSScript *script, ExecutionMode cmode)
return false; return false;
} }
static inline bool
CanIonCompile(JSFunction *fun, ExecutionMode cmode)
{
return fun->isInterpreted() && CanIonCompile(fun->nonLazyScript(), cmode);
}
static inline bool static inline bool
CompilingOffThread(JSScript *script, ExecutionMode cmode) CompilingOffThread(JSScript *script, ExecutionMode cmode)
{ {

View File

@ -271,6 +271,13 @@ IonBuilder::canInlineTarget(JSFunction *target, bool constructing)
return false; return false;
} }
// Allow constructing lazy scripts when performing the definite properties
// analysis, as baseline has not been used to warm the caller up yet.
if (target->isInterpretedLazy() && info().executionMode() == DefinitePropertiesAnalysis) {
if (!target->getOrCreateScript(cx))
return false;
}
if (!target->hasScript()) { if (!target->hasScript()) {
IonSpew(IonSpew_Inlining, "Cannot inline due to lack of Non-Lazy script"); IonSpew(IonSpew_Inlining, "Cannot inline due to lack of Non-Lazy script");
return false; return false;
@ -5447,7 +5454,7 @@ IonBuilder::jsop_initelem_array()
needStub = true; needStub = true;
} else if (!initializer->unknownProperties()) { } else if (!initializer->unknownProperties()) {
types::HeapTypeSetKey elemTypes = initializer->property(JSID_VOID); types::HeapTypeSetKey elemTypes = initializer->property(JSID_VOID);
if (!TypeSetIncludes(elemTypes.actualTypes, value->type(), value->resultTypeSet())) { if (!TypeSetIncludes(elemTypes.maybeTypes(), value->type(), value->resultTypeSet())) {
elemTypes.freeze(constraints()); elemTypes.freeze(constraints());
needStub = true; needStub = true;
} }
@ -5994,7 +6001,7 @@ IonBuilder::testSingletonProperty(JSObject *obj, JSObject *singleton,
if (objType->unknownProperties()) if (objType->unknownProperties())
return true; return true;
types::HeapTypeSetKey property = objType->property(idRoot); types::HeapTypeSetKey property = objType->property(NameToId(name), context());
if (obj != holder) { if (obj != holder) {
if (property.notEmpty(constraints())) if (property.notEmpty(constraints()))
return true; return true;
@ -6076,7 +6083,7 @@ IonBuilder::testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton,
if (object->unknownProperties()) if (object->unknownProperties())
return true; return true;
types::HeapTypeSetKey property = object->property(NameToId(name)); types::HeapTypeSetKey property = object->property(NameToId(name), context());
if (property.notEmpty(constraints())) if (property.notEmpty(constraints()))
return true; return true;
@ -6213,7 +6220,7 @@ IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psuc
types::TypeObjectKey *staticType = types::TypeObjectKey::get(staticObject); types::TypeObjectKey *staticType = types::TypeObjectKey::get(staticObject);
Maybe<types::HeapTypeSetKey> propertyTypes; Maybe<types::HeapTypeSetKey> propertyTypes;
if (!staticType->unknownProperties()) { if (!staticType->unknownProperties()) {
propertyTypes.construct(staticType->property(id)); propertyTypes.construct(staticType->property(id, context()));
if (propertyTypes.ref().configured(constraints(), staticType)) { if (propertyTypes.ref().configured(constraints(), staticType)) {
// The property has been reconfigured as non-configurable, non-enumerable // The property has been reconfigured as non-configurable, non-enumerable
// or non-writable. // or non-writable.
@ -6223,7 +6230,7 @@ IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psuc
} }
types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc); types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc);
bool barrier = PropertyReadNeedsTypeBarrier(cx, constraints(), staticType, bool barrier = PropertyReadNeedsTypeBarrier(cx, context(), constraints(), staticType,
name, baseTypes, /* updateObserved = */ true); name, baseTypes, /* updateObserved = */ true);
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes); types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
@ -6266,6 +6273,9 @@ IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psuc
bool bool
jit::TypeSetIncludes(types::TypeSet *types, MIRType input, types::TypeSet *inputTypes) jit::TypeSetIncludes(types::TypeSet *types, MIRType input, types::TypeSet *inputTypes)
{ {
if (!types)
return inputTypes && inputTypes->empty();
switch (input) { switch (input) {
case MIRType_Undefined: case MIRType_Undefined:
case MIRType_Null: case MIRType_Null:
@ -6324,7 +6334,7 @@ IonBuilder::setStaticName(JSObject *staticObject, PropertyName *name)
return jsop_setprop(name); return jsop_setprop(name);
} }
if (!TypeSetIncludes(propertyTypes.actualTypes, value->type(), value->resultTypeSet())) if (!TypeSetIncludes(propertyTypes.maybeTypes(), value->type(), value->resultTypeSet()))
return jsop_setprop(name); return jsop_setprop(name);
current->pop(); current->pop();
@ -6733,7 +6743,7 @@ IonBuilder::getElemTryCache(bool *emitted, MDefinition *obj, MDefinition *index)
// Emit GetElementCache. // Emit GetElementCache.
types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc); types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc);
bool barrier = PropertyReadNeedsTypeBarrier(cx, constraints(), obj, nullptr, baseTypes); bool barrier = PropertyReadNeedsTypeBarrier(cx, context(), constraints(), obj, nullptr, baseTypes);
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes); types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
// Always add a barrier if the index might be a string, so that the cache // Always add a barrier if the index might be a string, so that the cache
@ -6782,7 +6792,7 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
return false; return false;
} }
bool barrier = PropertyReadNeedsTypeBarrier(cx, constraints(), obj, nullptr, baseTypes); bool barrier = PropertyReadNeedsTypeBarrier(cx, context(), constraints(), obj, nullptr, baseTypes);
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes); types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
bool needsHoleCheck = !ElementAccessIsPacked(constraints(), obj); bool needsHoleCheck = !ElementAccessIsPacked(constraints(), obj);
@ -7576,7 +7586,8 @@ IonBuilder::getDefiniteSlot(types::TemporaryTypeSet *types, PropertyName *name,
jsid id = NameToId(name); jsid id = NameToId(name);
*property = type->property(id); *property = type->property(id);
return property->actualTypes->definiteProperty() && return property->maybeTypes() &&
property->maybeTypes()->definiteProperty() &&
!property->configured(constraints(), type); !property->configured(constraints(), type);
} }
@ -7615,7 +7626,7 @@ TestTypeHasOwnProperty(types::TypeObjectKey *typeObj, PropertyName *name, bool &
{ {
cont = true; cont = true;
types::HeapTypeSetKey propSet = typeObj->property(NameToId(name)); types::HeapTypeSetKey propSet = typeObj->property(NameToId(name));
if (!propSet.actualTypes->empty()) if (propSet.maybeTypes() && !propSet.maybeTypes()->empty())
cont = false; cont = false;
// Note: Callers must explicitly freeze the property type set later on if optimizing. // Note: Callers must explicitly freeze the property type set later on if optimizing.
return true; return true;
@ -8032,7 +8043,7 @@ IonBuilder::jsop_getprop(PropertyName *name)
return emitted; return emitted;
types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc); types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc);
bool barrier = PropertyReadNeedsTypeBarrier(cx, constraints(), bool barrier = PropertyReadNeedsTypeBarrier(cx, context(), constraints(),
current->peek(-1), name, baseTypes); current->peek(-1), name, baseTypes);
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes); types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
@ -8042,13 +8053,14 @@ IonBuilder::jsop_getprop(PropertyName *name)
// Except when loading constants above, always use a call if we are doing // Except when loading constants above, always use a call if we are doing
// the definite properties analysis and not actually emitting code, to // the definite properties analysis and not actually emitting code, to
// simplify later analysis. // simplify later analysis. Also skip deeper analysis if there are no known
if (info().executionMode() == DefinitePropertiesAnalysis) { // types for this operation, as it will always invalidate when executing.
if (info().executionMode() == DefinitePropertiesAnalysis || baseTypes->empty()) {
MDefinition *obj = current->pop(); MDefinition *obj = current->pop();
MCallGetProperty *call = MCallGetProperty::New(obj, name); MCallGetProperty *call = MCallGetProperty::New(obj, name);
current->add(call); current->add(call);
current->push(call); current->push(call);
return resumeAfter(call); return resumeAfter(call) && pushTypeBarrier(call, types, true);
} }
// Try to emit loads from known binary data blocks // Try to emit loads from known binary data blocks
@ -8268,7 +8280,7 @@ IonBuilder::getPropTryDefiniteSlot(bool *emitted, PropertyName *name,
useObj = guard; useObj = guard;
} }
MLoadFixedSlot *fixed = MLoadFixedSlot::New(useObj, property.actualTypes->definiteSlot()); MLoadFixedSlot *fixed = MLoadFixedSlot::New(useObj, property.maybeTypes()->definiteSlot());
if (!barrier) if (!barrier)
fixed->setResultType(MIRTypeFromValueType(types->getKnownTypeTag())); fixed->setResultType(MIRTypeFromValueType(types->getKnownTypeTag()));
@ -8748,7 +8760,7 @@ IonBuilder::setPropTryDefiniteSlot(bool *emitted, MDefinition *obj,
if (!getDefiniteSlot(obj->resultTypeSet(), name, &property)) if (!getDefiniteSlot(obj->resultTypeSet(), name, &property))
return true; return true;
MStoreFixedSlot *fixed = MStoreFixedSlot::New(obj, property.actualTypes->definiteSlot(), value); MStoreFixedSlot *fixed = MStoreFixedSlot::New(obj, property.maybeTypes()->definiteSlot(), value);
current->add(fixed); current->add(fixed);
current->push(value); current->push(value);

View File

@ -690,6 +690,16 @@ class IonBuilder : public MIRGenerator
return callerBuilder_ != nullptr; return callerBuilder_ != nullptr;
} }
JSContext *context() {
// JSContexts are only available to IonBuilder when running on the main
// thread, which after bug 785905 will only occur when doing eager
// analyses with no available baseline information. Until this bug is
// completed, both the |cx| member and |context()| may be used.
if (info().executionMode() == DefinitePropertiesAnalysis)
return cx;
return NULL;
}
private: private:
bool init(); bool init();

View File

@ -221,7 +221,7 @@ IonBuilder::inlineArray(CallInfo &callInfo)
for (uint32_t i = 0; i < initLength; i++) { for (uint32_t i = 0; i < initLength; i++) {
MDefinition *value = callInfo.getArg(i); MDefinition *value = callInfo.getArg(i);
if (!TypeSetIncludes(elemTypes.actualTypes, value->type(), value->resultTypeSet())) { if (!TypeSetIncludes(elemTypes.maybeTypes(), value->type(), value->resultTypeSet())) {
elemTypes.freeze(constraints()); elemTypes.freeze(constraints());
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
} }
@ -332,7 +332,7 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
bool needsHoleCheck = thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED); bool needsHoleCheck = thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED);
bool maybeUndefined = returnTypes->hasType(types::Type::UndefinedType()); bool maybeUndefined = returnTypes->hasType(types::Type::UndefinedType());
bool barrier = PropertyReadNeedsTypeBarrier(cx, constraints(), bool barrier = PropertyReadNeedsTypeBarrier(cx, context(), constraints(),
callInfo.thisArg(), nullptr, returnTypes); callInfo.thisArg(), nullptr, returnTypes);
if (barrier) if (barrier)
returnType = MIRType_Value; returnType = MIRType_Value;

View File

@ -2780,12 +2780,12 @@ PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *const
// which are accounted for by type information, i.e. native data properties // which are accounted for by type information, i.e. native data properties
// and elements. // and elements.
if (object->unknownProperties()) if (object->unknownProperties() || observed->empty())
return true; return true;
jsid id = name ? NameToId(name) : JSID_VOID; jsid id = name ? NameToId(name) : JSID_VOID;
types::HeapTypeSetKey property = object->property(id); types::HeapTypeSetKey property = object->property(id);
if (!TypeSetIncludes(observed, MIRType_Value, property.actualTypes)) if (property.maybeTypes() && !TypeSetIncludes(observed, MIRType_Value, property.maybeTypes()))
return true; return true;
// Type information for singleton objects is not required to reflect the // Type information for singleton objects is not required to reflect the
@ -2807,7 +2807,8 @@ PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *const
} }
bool bool
jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *constraints, jit::PropertyReadNeedsTypeBarrier(JSContext *cx, JSContext *propertycx,
types::CompilerConstraintList *constraints,
types::TypeObjectKey *object, PropertyName *name, types::TypeObjectKey *object, PropertyName *name,
types::StackTypeSet *observed, bool updateObserved) types::StackTypeSet *observed, bool updateObserved)
{ {
@ -2820,11 +2821,18 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *
if (!obj->isNative()) if (!obj->isNative())
break; break;
Value v; types::TypeObjectKey *typeObj = types::TypeObjectKey::get(obj);
if (HasDataProperty(cx, obj, NameToId(name), &v)) { if (!typeObj->unknownProperties()) {
if (v.isUndefined()) types::HeapTypeSetKey property = typeObj->property(NameToId(name), propertycx);
if (property.maybeTypes()) {
types::TypeSet::TypeList types;
if (!property.maybeTypes()->enumerateTypes(&types))
return false;
if (types.length()) {
observed->addType(cx, types[0]);
break; break;
observed->addType(cx, types::GetValueType(v)); }
}
} }
obj = obj->getProto(); obj = obj->getProto();
@ -2835,7 +2843,8 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *
} }
bool bool
jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *constraints, jit::PropertyReadNeedsTypeBarrier(JSContext *cx, JSContext *propertycx,
types::CompilerConstraintList *constraints,
MDefinition *obj, PropertyName *name, MDefinition *obj, PropertyName *name,
types::StackTypeSet *observed) types::StackTypeSet *observed)
{ {
@ -2850,7 +2859,7 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *
for (size_t i = 0; i < types->getObjectCount(); i++) { for (size_t i = 0; i < types->getObjectCount(); i++) {
types::TypeObjectKey *object = types->getObject(i); types::TypeObjectKey *object = types->getObject(i);
if (object) { if (object) {
if (PropertyReadNeedsTypeBarrier(cx, constraints, object, name, if (PropertyReadNeedsTypeBarrier(cx, propertycx, constraints, object, name,
observed, updateObserved)) observed, updateObserved))
{ {
return true; return true;
@ -2983,7 +2992,10 @@ TryAddTypeBarrierForWrite(types::CompilerConstraintList *constraints,
jsid id = name ? NameToId(name) : JSID_VOID; jsid id = name ? NameToId(name) : JSID_VOID;
types::HeapTypeSetKey property = object->property(id); types::HeapTypeSetKey property = object->property(id);
if (TypeSetIncludes(property.actualTypes, (*pvalue)->type(), (*pvalue)->resultTypeSet())) if (!property.maybeTypes())
return false;
if (TypeSetIncludes(property.maybeTypes(), (*pvalue)->type(), (*pvalue)->resultTypeSet()))
return false; return false;
// This freeze is not required for correctness, but ensures that we // This freeze is not required for correctness, but ensures that we
@ -2994,8 +3006,8 @@ TryAddTypeBarrierForWrite(types::CompilerConstraintList *constraints,
if (aggregateProperty.empty()) { if (aggregateProperty.empty()) {
aggregateProperty.construct(property); aggregateProperty.construct(property);
} else { } else {
if (!aggregateProperty.ref().actualTypes->isSubset(property.actualTypes) || if (!aggregateProperty.ref().maybeTypes()->isSubset(property.maybeTypes()) ||
!property.actualTypes->isSubset(aggregateProperty.ref().actualTypes)) !property.maybeTypes()->isSubset(aggregateProperty.ref().maybeTypes()))
{ {
return false; return false;
} }
@ -3030,7 +3042,7 @@ TryAddTypeBarrierForWrite(types::CompilerConstraintList *constraints,
return false; return false;
types::TemporaryTypeSet *types = types::TemporaryTypeSet *types =
aggregateProperty.ref().actualTypes->clone(GetIonContext()->temp->lifoAlloc()); aggregateProperty.ref().maybeTypes()->clone(GetIonContext()->temp->lifoAlloc());
if (!types) if (!types)
return false; return false;
@ -3085,7 +3097,7 @@ jit::PropertyWriteNeedsTypeBarrier(types::CompilerConstraintList *constraints,
jsid id = name ? NameToId(name) : JSID_VOID; jsid id = name ? NameToId(name) : JSID_VOID;
types::HeapTypeSetKey property = object->property(id); types::HeapTypeSetKey property = object->property(id);
if (!TypeSetIncludes(property.actualTypes, (*pvalue)->type(), (*pvalue)->resultTypeSet())) { if (!TypeSetIncludes(property.maybeTypes(), (*pvalue)->type(), (*pvalue)->resultTypeSet())) {
// Either pobj or pvalue needs to be modified to filter out the // Either pobj or pvalue needs to be modified to filter out the
// types which the value could have but are not in the property, // types which the value could have but are not in the property,
// or a VM call is required. A VM call is always required if pobj // or a VM call is required. A VM call is always required if pobj
@ -3117,10 +3129,10 @@ jit::PropertyWriteNeedsTypeBarrier(types::CompilerConstraintList *constraints,
jsid id = name ? NameToId(name) : JSID_VOID; jsid id = name ? NameToId(name) : JSID_VOID;
types::HeapTypeSetKey property = object->property(id); types::HeapTypeSetKey property = object->property(id);
if (TypeSetIncludes(property.actualTypes, (*pvalue)->type(), (*pvalue)->resultTypeSet())) if (TypeSetIncludes(property.maybeTypes(), (*pvalue)->type(), (*pvalue)->resultTypeSet()))
continue; continue;
if (!property.actualTypes->empty() || excluded) if ((property.maybeTypes() && !property.maybeTypes()->empty()) || excluded)
return true; return true;
excluded = object->isTypeObject() ? object->asTypeObject() : object->asSingleObject()->getType(GetIonContext()->cx); excluded = object->isTypeObject() ? object->asTypeObject() : object->asSingleObject()->getType(GetIonContext()->cx);
} }

View File

@ -8993,10 +8993,12 @@ bool ElementAccessIsPacked(types::CompilerConstraintList *constraints, MDefiniti
bool ElementAccessHasExtraIndexedProperty(types::CompilerConstraintList *constraints, bool ElementAccessHasExtraIndexedProperty(types::CompilerConstraintList *constraints,
MDefinition *obj); MDefinition *obj);
MIRType DenseNativeElementType(types::CompilerConstraintList *constraints, MDefinition *obj); MIRType DenseNativeElementType(types::CompilerConstraintList *constraints, MDefinition *obj);
bool PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *constraints, bool PropertyReadNeedsTypeBarrier(JSContext *cx, JSContext *propertycx,
types::CompilerConstraintList *constraints,
types::TypeObjectKey *object, PropertyName *name, types::TypeObjectKey *object, PropertyName *name,
types::StackTypeSet *observed, bool updateObserved); types::StackTypeSet *observed, bool updateObserved);
bool PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *constraints, bool PropertyReadNeedsTypeBarrier(JSContext *cx, JSContext *propertycx,
types::CompilerConstraintList *constraints,
MDefinition *obj, PropertyName *name, MDefinition *obj, PropertyName *name,
types::StackTypeSet *observed); types::StackTypeSet *observed);
bool PropertyReadOnPrototypeNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *constraints, bool PropertyReadOnPrototypeNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *constraints,

View File

@ -336,6 +336,39 @@ TypeSet::isSubset(TypeSet *other)
return true; return true;
} }
bool
TypeSet::enumerateTypes(TypeList *list)
{
/* If any type is possible, there's no need to worry about specifics. */
if (flags & TYPE_FLAG_UNKNOWN)
return list->append(Type::UnknownType());
/* Enqueue type set members stored as bits. */
for (TypeFlags flag = 1; flag < TYPE_FLAG_ANYOBJECT; flag <<= 1) {
if (flags & flag) {
Type type = Type::PrimitiveType(TypeFlagPrimitive(flag));
if (!list->append(type))
return false;
}
}
/* If any object is possible, skip specifics. */
if (flags & TYPE_FLAG_ANYOBJECT)
return list->append(Type::AnyObjectType());
/* Enqueue specific object types. */
unsigned count = getObjectCount();
for (unsigned i = 0; i < count; i++) {
TypeObjectKey *object = getObject(i);
if (object) {
if (!list->append(Type::ObjectType(object)))
return false;
}
}
return true;
}
inline void inline void
TypeSet::addTypesToConstraint(JSContext *cx, TypeConstraint *constraint) TypeSet::addTypesToConstraint(JSContext *cx, TypeConstraint *constraint)
{ {
@ -343,38 +376,9 @@ TypeSet::addTypesToConstraint(JSContext *cx, TypeConstraint *constraint)
* Build all types in the set into a vector before triggering the * Build all types in the set into a vector before triggering the
* constraint, as doing so may modify this type set. * constraint, as doing so may modify this type set.
*/ */
Vector<Type> types(cx); TypeList types;
if (!enumerateTypes(&types))
/* If any type is possible, there's no need to worry about specifics. */
if (flags & TYPE_FLAG_UNKNOWN) {
if (!types.append(Type::UnknownType()))
cx->compartment()->types.setPendingNukeTypes(cx); cx->compartment()->types.setPendingNukeTypes(cx);
} else {
/* Enqueue type set members stored as bits. */
for (TypeFlags flag = 1; flag < TYPE_FLAG_ANYOBJECT; flag <<= 1) {
if (flags & flag) {
Type type = Type::PrimitiveType(TypeFlagPrimitive(flag));
if (!types.append(type))
cx->compartment()->types.setPendingNukeTypes(cx);
}
}
/* If any object is possible, skip specifics. */
if (flags & TYPE_FLAG_ANYOBJECT) {
if (!types.append(Type::AnyObjectType()))
cx->compartment()->types.setPendingNukeTypes(cx);
} else {
/* Enqueue specific object types. */
unsigned count = getObjectCount();
for (unsigned i = 0; i < count; i++) {
TypeObjectKey *object = getObject(i);
if (object) {
if (!types.append(Type::ObjectType(object)))
cx->compartment()->types.setPendingNukeTypes(cx);
}
}
}
}
for (unsigned i = 0; i < types.length(); i++) for (unsigned i = 0; i < types.length(); i++)
constraint->newType(cx, this, types[i]); constraint->newType(cx, this, types[i]);
@ -566,10 +570,8 @@ class types::CompilerConstraint
CompilerConstraint(const HeapTypeSetKey &property) CompilerConstraint(const HeapTypeSetKey &property)
: property(property), : property(property),
expected(property.actualTypes->clone(IonAlloc())) expected(property.maybeTypes() ? property.maybeTypes()->clone(IonAlloc()) : NULL)
{ {}
// Note: CompilerConstraintList::add watches for OOM under clone().
}
// Generate the type constraint recording the assumption made by this // Generate the type constraint recording the assumption made by this
// compilation. Returns true if the assumption originally made still holds. // compilation. Returns true if the assumption originally made still holds.
@ -580,7 +582,7 @@ void
CompilerConstraintList::add(CompilerConstraint *constraint) CompilerConstraintList::add(CompilerConstraint *constraint)
{ {
#ifdef JS_ION #ifdef JS_ION
if (!constraint || !constraint->expected || !constraints.append(constraint)) if (!constraint || !constraints.append(constraint))
setFailed(); setFailed();
#else #else
MOZ_CRASH(); MOZ_CRASH();
@ -641,13 +643,16 @@ template <typename T>
bool bool
CompilerConstraintInstance<T>::generateTypeConstraint(JSContext *cx, RecompileInfo recompileInfo) CompilerConstraintInstance<T>::generateTypeConstraint(JSContext *cx, RecompileInfo recompileInfo)
{ {
if (property.actualObject->unknownProperties()) if (property.object()->unknownProperties())
return false;
if (!property.instantiate(cx))
return false; return false;
if (!data.constraintHolds(cx, property, expected)) if (!data.constraintHolds(cx, property, expected))
return false; return false;
property.actualTypes->add(cx, cx->typeLifoAlloc().new_<TypeCompilerConstraint<T> >(recompileInfo, data), property.maybeTypes()->add(cx, cx->typeLifoAlloc().new_<TypeCompilerConstraint<T> >(recompileInfo, data),
/* callExisting = */ false); /* callExisting = */ false);
return true; return true;
} }
@ -683,37 +688,62 @@ TypeObjectKey::newScript()
return nullptr; return nullptr;
} }
TypeObject *
TypeObjectKey::maybeType()
{
if (isTypeObject())
return asTypeObject();
if (asSingleObject()->hasLazyType())
return NULL;
return asSingleObject()->type();
}
bool bool
TypeObjectKey::unknownProperties() TypeObjectKey::unknownProperties()
{ {
#ifdef JS_ION if (TypeObject *type = maybeType())
JSContext *cx = jit::GetIonContext()->cx;
TypeObject *type = isSingleObject() ? asSingleObject()->getType(cx) : asTypeObject();
if (!type)
MOZ_CRASH();
return type->unknownProperties(); return type->unknownProperties();
#else return false;
MOZ_CRASH();
#endif
} }
HeapTypeSetKey HeapTypeSetKey
TypeObjectKey::property(jsid id) TypeObjectKey::property(jsid id, JSContext *maybecx /* = NULL */)
{ {
#ifdef JS_ION JS_ASSERT(!unknownProperties());
JSContext *cx = jit::GetIonContext()->cx;
TypeObject *type = isSingleObject() ? asSingleObject()->getType(cx) : asTypeObject();
if (!type)
MOZ_CRASH();
HeapTypeSetKey property; HeapTypeSetKey property;
property.actualObject = type; property.object_ = this;
property.actualTypes = type->getProperty(cx, id); property.id_ = id;
if (!property.actualTypes) if (TypeObject *type = maybeType())
MOZ_CRASH(); property.maybeTypes_ = type->maybeGetProperty(id);
#ifdef JS_ION
// If we are accessing a lazily defined property which actually exists in
// the VM and has not been instantiated yet, instantiate it now if we are
// on the main thread and able to do so.
if (maybecx && !property.maybeTypes() && !JSID_IS_VOID(id) && !JSID_IS_EMPTY(id)) {
JS_ASSERT(CurrentThreadCanAccessRuntime(maybecx->runtime()));
JSObject *singleton = isSingleObject() ? asSingleObject() : asTypeObject()->singleton;
if (singleton && singleton->isNative() && singleton->nativeLookupPure(id)) {
EnsureTrackPropertyTypes(maybecx, singleton, id);
if (TypeObject *type = maybeType())
property.maybeTypes_ = type->maybeGetProperty(id);
}
}
#endif // JS_ION
return property; return property;
#else }
MOZ_CRASH();
#endif bool
HeapTypeSetKey::instantiate(JSContext *cx)
{
if (maybeTypes())
return true;
if (object()->isSingleObject() && !object()->asSingleObject()->getType(cx))
return false;
maybeTypes_ = object()->maybeType()->getProperty(cx, id());
return maybeTypes_ != NULL;
} }
bool bool
@ -738,13 +768,18 @@ types::FinishCompilation(JSContext *cx, JSScript *script, ExecutionMode executio
*precompileInfo = RecompileInfo(index); *precompileInfo = RecompileInfo(index);
bool succeeded = true;
for (size_t i = 0; i < constraints->length(); i++) { for (size_t i = 0; i < constraints->length(); i++) {
CompilerConstraint *constraint = constraints->get(i); CompilerConstraint *constraint = constraints->get(i);
if (!constraint->generateTypeConstraint(cx, *precompileInfo)) { if (!constraint->generateTypeConstraint(cx, *precompileInfo))
succeeded = false;
}
if (!succeeded) {
types.constrainedOutputs->back().invalidate(); types.constrainedOutputs->back().invalidate();
return false; return false;
} }
}
return true; return true;
} }
@ -766,7 +801,9 @@ class ConstraintDataFreeze
bool constraintHolds(JSContext *cx, bool constraintHolds(JSContext *cx,
const HeapTypeSetKey &property, TemporaryTypeSet *expected) const HeapTypeSetKey &property, TemporaryTypeSet *expected)
{ {
return property.actualTypes->isSubset(expected); return expected
? property.maybeTypes()->isSubset(expected)
: property.maybeTypes()->empty();
} }
}; };
@ -842,13 +879,15 @@ TemporaryTypeSet::mightBeType(JSValueType type)
JSValueType JSValueType
HeapTypeSetKey::knownTypeTag(CompilerConstraintList *constraints) HeapTypeSetKey::knownTypeTag(CompilerConstraintList *constraints)
{ {
if (actualTypes->unknown()) TypeSet *types = maybeTypes();
if (!types || types->unknown())
return JSVAL_TYPE_UNKNOWN; return JSVAL_TYPE_UNKNOWN;
TypeFlags flags = actualTypes->baseFlags() & ~TYPE_FLAG_ANYOBJECT; TypeFlags flags = types->baseFlags() & ~TYPE_FLAG_ANYOBJECT;
JSValueType type; JSValueType type;
if (actualTypes->unknownObject() || actualTypes->getObjectCount()) if (types->unknownObject() || types->getObjectCount())
type = flags ? JSVAL_TYPE_UNKNOWN : JSVAL_TYPE_OBJECT; type = flags ? JSVAL_TYPE_UNKNOWN : JSVAL_TYPE_OBJECT;
else else
type = GetValueTypeFromTypeFlags(flags); type = GetValueTypeFromTypeFlags(flags);
@ -863,7 +902,7 @@ HeapTypeSetKey::knownTypeTag(CompilerConstraintList *constraints)
* that the exact tag is unknown, as it will stay unknown as more types are * that the exact tag is unknown, as it will stay unknown as more types are
* added to the set. * added to the set.
*/ */
JS_ASSERT_IF(actualTypes->empty(), type == JSVAL_TYPE_UNKNOWN); JS_ASSERT_IF(types->empty(), type == JSVAL_TYPE_UNKNOWN);
return type; return type;
} }
@ -871,7 +910,7 @@ HeapTypeSetKey::knownTypeTag(CompilerConstraintList *constraints)
bool bool
HeapTypeSetKey::notEmpty(CompilerConstraintList *constraints) HeapTypeSetKey::notEmpty(CompilerConstraintList *constraints)
{ {
if (!actualTypes->empty()) if (maybeTypes() && !maybeTypes()->empty())
return true; return true;
freeze(constraints); freeze(constraints);
return false; return false;
@ -880,7 +919,11 @@ HeapTypeSetKey::notEmpty(CompilerConstraintList *constraints)
bool bool
HeapTypeSetKey::knownSubset(CompilerConstraintList *constraints, const HeapTypeSetKey &other) HeapTypeSetKey::knownSubset(CompilerConstraintList *constraints, const HeapTypeSetKey &other)
{ {
if (!actualTypes->isSubset(other.actualTypes)) if (!maybeTypes() || maybeTypes()->empty()) {
freeze(constraints);
return true;
}
if (!other.maybeTypes() || !maybeTypes()->isSubset(other.maybeTypes()))
return false; return false;
freeze(constraints); freeze(constraints);
return true; return true;
@ -898,10 +941,12 @@ TemporaryTypeSet::getSingleton()
JSObject * JSObject *
HeapTypeSetKey::singleton(CompilerConstraintList *constraints) HeapTypeSetKey::singleton(CompilerConstraintList *constraints)
{ {
if (actualTypes->baseFlags() != 0 || actualTypes->getObjectCount() != 1) TypeSet *types = maybeTypes();
if (!types || types->baseFlags() != 0 || types->getObjectCount() != 1)
return nullptr; return nullptr;
JSObject *obj = actualTypes->getSingleObject(0); JSObject *obj = types->getSingleObject(0);
if (obj) if (obj)
freeze(constraints); freeze(constraints);
@ -912,9 +957,12 @@ HeapTypeSetKey::singleton(CompilerConstraintList *constraints)
bool bool
HeapTypeSetKey::needsBarrier(CompilerConstraintList *constraints) HeapTypeSetKey::needsBarrier(CompilerConstraintList *constraints)
{ {
bool result = actualTypes->unknownObject() TypeSet *types = maybeTypes();
|| actualTypes->getObjectCount() > 0 if (!types)
|| actualTypes->hasAnyFlag(TYPE_FLAG_STRING); return false;
bool result = types->unknownObject()
|| types->getObjectCount() > 0
|| types->hasAnyFlag(TYPE_FLAG_STRING);
if (!result) if (!result)
freeze(constraints); freeze(constraints);
return result; return result;
@ -946,7 +994,7 @@ class ConstraintDataFreezeObjectFlags
bool constraintHolds(JSContext *cx, bool constraintHolds(JSContext *cx,
const HeapTypeSetKey &property, TemporaryTypeSet *expected) const HeapTypeSetKey &property, TemporaryTypeSet *expected)
{ {
return !invalidateOnNewObjectState(property.actualObject); return !invalidateOnNewObjectState(property.object()->maybeType());
} }
}; };
@ -955,22 +1003,16 @@ class ConstraintDataFreezeObjectFlags
bool bool
TypeObjectKey::hasFlags(CompilerConstraintList *constraints, TypeObjectFlags flags) TypeObjectKey::hasFlags(CompilerConstraintList *constraints, TypeObjectFlags flags)
{ {
#ifdef JS_ION
JS_ASSERT(flags); JS_ASSERT(flags);
JSContext *cx = jit::GetIonContext()->cx; if (TypeObject *type = maybeType()) {
TypeObject *type = isSingleObject() ? asSingleObject()->getType(cx) : asTypeObject();
if (!type)
MOZ_CRASH();
if (type->hasAnyFlags(flags)) if (type->hasAnyFlags(flags))
return true; return true;
}
HeapTypeSetKey objectProperty = property(JSID_EMPTY); HeapTypeSetKey objectProperty = property(JSID_EMPTY);
constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectFlags> >(objectProperty, ConstraintDataFreezeObjectFlags(flags))); constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectFlags> >(objectProperty, ConstraintDataFreezeObjectFlags(flags)));
return false; return false;
#else
MOZ_CRASH();
#endif
} }
bool bool
@ -1047,7 +1089,7 @@ class ConstraintDataFreezeObjectForNewScriptTemplate
bool constraintHolds(JSContext *cx, bool constraintHolds(JSContext *cx,
const HeapTypeSetKey &property, TemporaryTypeSet *expected) const HeapTypeSetKey &property, TemporaryTypeSet *expected)
{ {
return !invalidateOnNewObjectState(property.actualObject); return !invalidateOnNewObjectState(property.object()->maybeType());
} }
}; };
@ -1073,7 +1115,7 @@ class ConstraintDataFreezeObjectForTypedArrayBuffer
bool constraintHolds(JSContext *cx, bool constraintHolds(JSContext *cx,
const HeapTypeSetKey &property, TemporaryTypeSet *expected) const HeapTypeSetKey &property, TemporaryTypeSet *expected)
{ {
return !invalidateOnNewObjectState(property.actualObject); return !invalidateOnNewObjectState(property.object()->maybeType());
} }
}; };
@ -1170,7 +1212,7 @@ class ConstraintDataFreezeConfiguredProperty
} }
} }
return !property.actualTypes->configuredProperty(); return !property.maybeTypes()->configuredProperty();
} }
}; };
@ -1179,7 +1221,7 @@ class ConstraintDataFreezeConfiguredProperty
bool bool
HeapTypeSetKey::configured(CompilerConstraintList *constraints, TypeObjectKey *type) HeapTypeSetKey::configured(CompilerConstraintList *constraints, TypeObjectKey *type)
{ {
if (actualTypes->configuredProperty()) if (maybeTypes() && maybeTypes()->configuredProperty())
return true; return true;
constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeConfiguredProperty> >(*this, ConstraintDataFreezeConfiguredProperty(type))); constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeConfiguredProperty> >(*this, ConstraintDataFreezeConfiguredProperty(type)));
@ -1255,7 +1297,8 @@ TemporaryTypeSet::convertDoubleElements(CompilerConstraintList *constraints)
// double in their element types (as the conversion may render the type // double in their element types (as the conversion may render the type
// information incorrect), nor for non-array objects (as their elements // information incorrect), nor for non-array objects (as their elements
// may point to emptyObjectElements, which cannot be converted). // may point to emptyObjectElements, which cannot be converted).
if (!property.actualTypes->hasType(Type::DoubleType()) || if (!property.maybeTypes() ||
!property.maybeTypes()->hasType(Type::DoubleType()) ||
type->clasp() != &ArrayObject::class_) type->clasp() != &ArrayObject::class_)
{ {
dontConvert = true; dontConvert = true;
@ -1763,15 +1806,9 @@ bool
types::ArrayPrototypeHasIndexedProperty(CompilerConstraintList *constraints, types::ArrayPrototypeHasIndexedProperty(CompilerConstraintList *constraints,
HandleScript script) HandleScript script)
{ {
#ifdef JS_ION if (JSObject *proto = script->global().maybeGetArrayPrototype())
JSObject *proto = script->global().getOrCreateArrayPrototype(jit::GetIonContext()->cx);
if (!proto)
return true;
return PrototypeHasIndexedProperty(constraints, proto); return PrototypeHasIndexedProperty(constraints, proto);
#else return true;
MOZ_CRASH();
#endif
} }
bool bool

View File

@ -177,8 +177,7 @@ namespace types {
class TypeCompartment; class TypeCompartment;
class TypeSet; class TypeSet;
class TypeObjectKey;
struct TypeObjectKey;
/* /*
* Information about a single concrete type. We pack this into a single word, * Information about a single concrete type. We pack this into a single word,
@ -543,6 +542,10 @@ class TypeSet
/* Mark this type set as representing a configured property. */ /* Mark this type set as representing a configured property. */
inline void setConfiguredProperty(ExclusiveContext *cx); inline void setConfiguredProperty(ExclusiveContext *cx);
/* Get a list of all types in this set. */
typedef Vector<Type, 1, SystemAllocPolicy> TypeList;
bool enumerateTypes(TypeList *list);
/* /*
* Iterate through the objects in this set. getObjectCount overapproximates * Iterate through the objects in this set. getObjectCount overapproximates
* in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject * in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject
@ -1219,8 +1222,9 @@ typedef HashMap<AllocationSiteKey,ReadBarriered<TypeObject>,AllocationSiteKey,Sy
class HeapTypeSetKey; class HeapTypeSetKey;
/* Type set entry for either a JSObject with singleton type or a non-singleton TypeObject. */ // Type set entry for either a JSObject with singleton type or a non-singleton TypeObject.
struct TypeObjectKey { struct TypeObjectKey
{
static intptr_t keyBits(TypeObjectKey *obj) { return (intptr_t) obj; } static intptr_t keyBits(TypeObjectKey *obj) { return (intptr_t) obj; }
static TypeObjectKey *getKey(TypeObjectKey *obj) { return obj; } static TypeObjectKey *getKey(TypeObjectKey *obj) { return obj; }
@ -1259,14 +1263,40 @@ struct TypeObjectKey {
void watchStateChangeForInlinedCall(CompilerConstraintList *constraints); void watchStateChangeForInlinedCall(CompilerConstraintList *constraints);
void watchStateChangeForNewScriptTemplate(CompilerConstraintList *constraints); void watchStateChangeForNewScriptTemplate(CompilerConstraintList *constraints);
void watchStateChangeForTypedArrayBuffer(CompilerConstraintList *constraints); void watchStateChangeForTypedArrayBuffer(CompilerConstraintList *constraints);
HeapTypeSetKey property(jsid id); HeapTypeSetKey property(jsid id, JSContext *maybecx = NULL);
TypeObject *maybeType();
}; };
// Representation of a heap type property which may or may not be instantiated.
// Heap properties for singleton types are instantiated lazily as they are used
// by the compiler, but this is only done on the main thread. If we are
// compiling off thread and use a property which has not yet been instantiated,
// it will be treated as empty and non-configured and will be instantiated when
// rejoining to the main thread. If it is in fact not empty, the compilation
// will fail; to avoid this, we try to instantiate singleton property types
// during generation of baseline caches.
class HeapTypeSetKey class HeapTypeSetKey
{ {
friend class TypeObjectKey;
// Object and property being accessed.
TypeObjectKey *object_;
jsid id_;
// If instantiated, the underlying heap type set.
HeapTypeSet *maybeTypes_;
public: public:
TypeObject *actualObject; HeapTypeSetKey()
HeapTypeSet *actualTypes; : object_(NULL), id_(JSID_EMPTY), maybeTypes_(NULL)
{}
TypeObjectKey *object() const { return object_; }
jsid id() const { return id_; }
HeapTypeSet *maybeTypes() const { return maybeTypes_; }
bool instantiate(JSContext *cx);
void freeze(CompilerConstraintList *constraints); void freeze(CompilerConstraintList *constraints);
JSValueType knownTypeTag(CompilerConstraintList *constraints); JSValueType knownTypeTag(CompilerConstraintList *constraints);

View File

@ -422,15 +422,18 @@ TrackPropertyTypes(ExclusiveContext *cx, JSObject *obj, jsid id)
inline void inline void
EnsureTrackPropertyTypes(JSContext *cx, JSObject *obj, jsid id) EnsureTrackPropertyTypes(JSContext *cx, JSObject *obj, jsid id)
{ {
JS_ASSERT(!obj->hasLazyType()); if (!cx->typeInferenceEnabled())
if (!cx->typeInferenceEnabled() || obj->type()->unknownProperties())
return; return;
id = IdToTypeId(id); id = IdToTypeId(id);
if (obj->hasSingletonType()) { if (obj->hasSingletonType()) {
AutoEnterAnalysis enter(cx); AutoEnterAnalysis enter(cx);
if (obj->hasLazyType() && !obj->getType(cx)) {
cx->compartment()->types.setPendingNukeTypes(cx);
return;
}
if (!obj->type()->unknownProperties())
obj->type()->getProperty(cx, id); obj->type()->getProperty(cx, id);
} }

View File

@ -287,6 +287,12 @@ class GlobalObject : public JSObject
return &self->getPrototype(JSProto_Array).toObject(); return &self->getPrototype(JSProto_Array).toObject();
} }
JSObject *maybeGetArrayPrototype() {
if (arrayClassInitialized())
return &getPrototype(JSProto_Array).toObject();
return NULL;
}
JSObject *getOrCreateBooleanPrototype(JSContext *cx) { JSObject *getOrCreateBooleanPrototype(JSContext *cx) {
if (booleanClassInitialized()) if (booleanClassInitialized())
return &getPrototype(JSProto_Boolean).toObject(); return &getPrototype(JSProto_Boolean).toObject();