mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 924611 - Don't create lazy type objects and type properties in IonBuilder, r=jandem.
This commit is contained in:
parent
251cbba440
commit
724613f48e
@ -1368,9 +1368,6 @@ ICUpdatedStub::addUpdateStubForValue(JSContext *cx, HandleScript script, HandleO
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!obj->getType(cx))
|
||||
return false;
|
||||
|
||||
types::EnsureTrackPropertyTypes(cx, obj, id);
|
||||
|
||||
if (val.isPrimitive()) {
|
||||
@ -5326,6 +5323,10 @@ TryAttachGlobalNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback *
|
||||
|
||||
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.
|
||||
RootedShape shape(cx, global->nativeLookup(cx, id));
|
||||
if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot())
|
||||
@ -5383,6 +5384,10 @@ TryAttachScopeNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback *s
|
||||
if (!IsCacheableGetPropReadSlot(scopeChain, scopeChain, shape))
|
||||
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;
|
||||
uint32_t offset;
|
||||
GetFixedOrDynamicSlotOffset(scopeChain, shape->slot(), &isFixedSlot, &offset);
|
||||
@ -5810,6 +5815,10 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
|
||||
uint32_t 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::GetProp_NativePrototype;
|
||||
|
||||
@ -5919,6 +5928,10 @@ TryAttachStringGetPropStub(JSContext *cx, HandleScript script, ICGetProp_Fallbac
|
||||
if (!stringProto)
|
||||
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
|
||||
RootedId propId(cx, NameToId(name));
|
||||
RootedShape shape(cx, stringProto->nativeLookup(cx, propId));
|
||||
@ -7465,6 +7478,11 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsb
|
||||
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,
|
||||
" Generating Call_Scripted stub (fun=%p, %s:%d, cons=%s)",
|
||||
fun.get(), fun->nonLazyScript()->filename(), fun->nonLazyScript()->lineno,
|
||||
|
@ -2151,7 +2151,7 @@ CodeGenerator::visitApplyArgsGeneric(LApplyArgsGeneric *apply)
|
||||
ExecutionMode executionMode = gen->info().executionMode();
|
||||
if (apply->hasSingleTarget()) {
|
||||
JSFunction *target = apply->getSingleTarget();
|
||||
if (!CanIonCompile(target, executionMode)) {
|
||||
if (target->isNative()) {
|
||||
if (!emitCallInvokeFunction(apply, copyreg))
|
||||
return false;
|
||||
emitPopArguments(apply, copyreg);
|
||||
|
@ -73,12 +73,6 @@ CanIonCompile(JSScript *script, ExecutionMode cmode)
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
CanIonCompile(JSFunction *fun, ExecutionMode cmode)
|
||||
{
|
||||
return fun->isInterpreted() && CanIonCompile(fun->nonLazyScript(), cmode);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
CompilingOffThread(JSScript *script, ExecutionMode cmode)
|
||||
{
|
||||
|
@ -271,6 +271,13 @@ IonBuilder::canInlineTarget(JSFunction *target, bool constructing)
|
||||
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()) {
|
||||
IonSpew(IonSpew_Inlining, "Cannot inline due to lack of Non-Lazy script");
|
||||
return false;
|
||||
@ -5447,7 +5454,7 @@ IonBuilder::jsop_initelem_array()
|
||||
needStub = true;
|
||||
} else if (!initializer->unknownProperties()) {
|
||||
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());
|
||||
needStub = true;
|
||||
}
|
||||
@ -5994,7 +6001,7 @@ IonBuilder::testSingletonProperty(JSObject *obj, JSObject *singleton,
|
||||
if (objType->unknownProperties())
|
||||
return true;
|
||||
|
||||
types::HeapTypeSetKey property = objType->property(idRoot);
|
||||
types::HeapTypeSetKey property = objType->property(NameToId(name), context());
|
||||
if (obj != holder) {
|
||||
if (property.notEmpty(constraints()))
|
||||
return true;
|
||||
@ -6076,7 +6083,7 @@ IonBuilder::testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton,
|
||||
|
||||
if (object->unknownProperties())
|
||||
return true;
|
||||
types::HeapTypeSetKey property = object->property(NameToId(name));
|
||||
types::HeapTypeSetKey property = object->property(NameToId(name), context());
|
||||
if (property.notEmpty(constraints()))
|
||||
return true;
|
||||
|
||||
@ -6213,7 +6220,7 @@ IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psuc
|
||||
types::TypeObjectKey *staticType = types::TypeObjectKey::get(staticObject);
|
||||
Maybe<types::HeapTypeSetKey> propertyTypes;
|
||||
if (!staticType->unknownProperties()) {
|
||||
propertyTypes.construct(staticType->property(id));
|
||||
propertyTypes.construct(staticType->property(id, context()));
|
||||
if (propertyTypes.ref().configured(constraints(), staticType)) {
|
||||
// The property has been reconfigured as non-configurable, non-enumerable
|
||||
// or non-writable.
|
||||
@ -6223,7 +6230,7 @@ IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psuc
|
||||
}
|
||||
|
||||
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);
|
||||
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
|
||||
|
||||
@ -6266,6 +6273,9 @@ IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psuc
|
||||
bool
|
||||
jit::TypeSetIncludes(types::TypeSet *types, MIRType input, types::TypeSet *inputTypes)
|
||||
{
|
||||
if (!types)
|
||||
return inputTypes && inputTypes->empty();
|
||||
|
||||
switch (input) {
|
||||
case MIRType_Undefined:
|
||||
case MIRType_Null:
|
||||
@ -6324,7 +6334,7 @@ IonBuilder::setStaticName(JSObject *staticObject, PropertyName *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);
|
||||
|
||||
current->pop();
|
||||
@ -6733,7 +6743,7 @@ IonBuilder::getElemTryCache(bool *emitted, MDefinition *obj, MDefinition *index)
|
||||
// Emit GetElementCache.
|
||||
|
||||
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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, constraints(), obj, nullptr, baseTypes);
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, context(), constraints(), obj, nullptr, baseTypes);
|
||||
types::TemporaryTypeSet *types = cloneTypeSet(baseTypes);
|
||||
|
||||
bool needsHoleCheck = !ElementAccessIsPacked(constraints(), obj);
|
||||
@ -7576,7 +7586,8 @@ IonBuilder::getDefiniteSlot(types::TemporaryTypeSet *types, PropertyName *name,
|
||||
jsid id = NameToId(name);
|
||||
|
||||
*property = type->property(id);
|
||||
return property->actualTypes->definiteProperty() &&
|
||||
return property->maybeTypes() &&
|
||||
property->maybeTypes()->definiteProperty() &&
|
||||
!property->configured(constraints(), type);
|
||||
}
|
||||
|
||||
@ -7615,7 +7626,7 @@ TestTypeHasOwnProperty(types::TypeObjectKey *typeObj, PropertyName *name, bool &
|
||||
{
|
||||
cont = true;
|
||||
types::HeapTypeSetKey propSet = typeObj->property(NameToId(name));
|
||||
if (!propSet.actualTypes->empty())
|
||||
if (propSet.maybeTypes() && !propSet.maybeTypes()->empty())
|
||||
cont = false;
|
||||
// Note: Callers must explicitly freeze the property type set later on if optimizing.
|
||||
return true;
|
||||
@ -8032,7 +8043,7 @@ IonBuilder::jsop_getprop(PropertyName *name)
|
||||
return emitted;
|
||||
|
||||
types::StackTypeSet *baseTypes = types::TypeScript::BytecodeTypes(script(), pc);
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, constraints(),
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, context(), constraints(),
|
||||
current->peek(-1), name, 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
|
||||
// the definite properties analysis and not actually emitting code, to
|
||||
// simplify later analysis.
|
||||
if (info().executionMode() == DefinitePropertiesAnalysis) {
|
||||
// simplify later analysis. Also skip deeper analysis if there are no known
|
||||
// types for this operation, as it will always invalidate when executing.
|
||||
if (info().executionMode() == DefinitePropertiesAnalysis || baseTypes->empty()) {
|
||||
MDefinition *obj = current->pop();
|
||||
MCallGetProperty *call = MCallGetProperty::New(obj, name);
|
||||
current->add(call);
|
||||
current->push(call);
|
||||
return resumeAfter(call);
|
||||
return resumeAfter(call) && pushTypeBarrier(call, types, true);
|
||||
}
|
||||
|
||||
// Try to emit loads from known binary data blocks
|
||||
@ -8268,7 +8280,7 @@ IonBuilder::getPropTryDefiniteSlot(bool *emitted, PropertyName *name,
|
||||
useObj = guard;
|
||||
}
|
||||
|
||||
MLoadFixedSlot *fixed = MLoadFixedSlot::New(useObj, property.actualTypes->definiteSlot());
|
||||
MLoadFixedSlot *fixed = MLoadFixedSlot::New(useObj, property.maybeTypes()->definiteSlot());
|
||||
if (!barrier)
|
||||
fixed->setResultType(MIRTypeFromValueType(types->getKnownTypeTag()));
|
||||
|
||||
@ -8748,7 +8760,7 @@ IonBuilder::setPropTryDefiniteSlot(bool *emitted, MDefinition *obj,
|
||||
if (!getDefiniteSlot(obj->resultTypeSet(), name, &property))
|
||||
return true;
|
||||
|
||||
MStoreFixedSlot *fixed = MStoreFixedSlot::New(obj, property.actualTypes->definiteSlot(), value);
|
||||
MStoreFixedSlot *fixed = MStoreFixedSlot::New(obj, property.maybeTypes()->definiteSlot(), value);
|
||||
current->add(fixed);
|
||||
current->push(value);
|
||||
|
||||
|
@ -690,6 +690,16 @@ class IonBuilder : public MIRGenerator
|
||||
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:
|
||||
bool init();
|
||||
|
||||
|
@ -221,7 +221,7 @@ IonBuilder::inlineArray(CallInfo &callInfo)
|
||||
|
||||
for (uint32_t i = 0; i < initLength; 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());
|
||||
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 maybeUndefined = returnTypes->hasType(types::Type::UndefinedType());
|
||||
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, constraints(),
|
||||
bool barrier = PropertyReadNeedsTypeBarrier(cx, context(), constraints(),
|
||||
callInfo.thisArg(), nullptr, returnTypes);
|
||||
if (barrier)
|
||||
returnType = MIRType_Value;
|
||||
|
@ -2780,12 +2780,12 @@ PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *const
|
||||
// which are accounted for by type information, i.e. native data properties
|
||||
// and elements.
|
||||
|
||||
if (object->unknownProperties())
|
||||
if (object->unknownProperties() || observed->empty())
|
||||
return true;
|
||||
|
||||
jsid id = name ? NameToId(name) : JSID_VOID;
|
||||
types::HeapTypeSetKey property = object->property(id);
|
||||
if (!TypeSetIncludes(observed, MIRType_Value, property.actualTypes))
|
||||
if (property.maybeTypes() && !TypeSetIncludes(observed, MIRType_Value, property.maybeTypes()))
|
||||
return true;
|
||||
|
||||
// Type information for singleton objects is not required to reflect the
|
||||
@ -2807,7 +2807,8 @@ PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *const
|
||||
}
|
||||
|
||||
bool
|
||||
jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *constraints,
|
||||
jit::PropertyReadNeedsTypeBarrier(JSContext *cx, JSContext *propertycx,
|
||||
types::CompilerConstraintList *constraints,
|
||||
types::TypeObjectKey *object, PropertyName *name,
|
||||
types::StackTypeSet *observed, bool updateObserved)
|
||||
{
|
||||
@ -2820,11 +2821,18 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *
|
||||
if (!obj->isNative())
|
||||
break;
|
||||
|
||||
Value v;
|
||||
if (HasDataProperty(cx, obj, NameToId(name), &v)) {
|
||||
if (v.isUndefined())
|
||||
break;
|
||||
observed->addType(cx, types::GetValueType(v));
|
||||
types::TypeObjectKey *typeObj = types::TypeObjectKey::get(obj);
|
||||
if (!typeObj->unknownProperties()) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
obj = obj->getProto();
|
||||
@ -2835,7 +2843,8 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *
|
||||
}
|
||||
|
||||
bool
|
||||
jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *constraints,
|
||||
jit::PropertyReadNeedsTypeBarrier(JSContext *cx, JSContext *propertycx,
|
||||
types::CompilerConstraintList *constraints,
|
||||
MDefinition *obj, PropertyName *name,
|
||||
types::StackTypeSet *observed)
|
||||
{
|
||||
@ -2850,7 +2859,7 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *
|
||||
for (size_t i = 0; i < types->getObjectCount(); i++) {
|
||||
types::TypeObjectKey *object = types->getObject(i);
|
||||
if (object) {
|
||||
if (PropertyReadNeedsTypeBarrier(cx, constraints, object, name,
|
||||
if (PropertyReadNeedsTypeBarrier(cx, propertycx, constraints, object, name,
|
||||
observed, updateObserved))
|
||||
{
|
||||
return true;
|
||||
@ -2983,7 +2992,10 @@ TryAddTypeBarrierForWrite(types::CompilerConstraintList *constraints,
|
||||
|
||||
jsid id = name ? NameToId(name) : JSID_VOID;
|
||||
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;
|
||||
|
||||
// This freeze is not required for correctness, but ensures that we
|
||||
@ -2994,8 +3006,8 @@ TryAddTypeBarrierForWrite(types::CompilerConstraintList *constraints,
|
||||
if (aggregateProperty.empty()) {
|
||||
aggregateProperty.construct(property);
|
||||
} else {
|
||||
if (!aggregateProperty.ref().actualTypes->isSubset(property.actualTypes) ||
|
||||
!property.actualTypes->isSubset(aggregateProperty.ref().actualTypes))
|
||||
if (!aggregateProperty.ref().maybeTypes()->isSubset(property.maybeTypes()) ||
|
||||
!property.maybeTypes()->isSubset(aggregateProperty.ref().maybeTypes()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -3030,7 +3042,7 @@ TryAddTypeBarrierForWrite(types::CompilerConstraintList *constraints,
|
||||
return false;
|
||||
|
||||
types::TemporaryTypeSet *types =
|
||||
aggregateProperty.ref().actualTypes->clone(GetIonContext()->temp->lifoAlloc());
|
||||
aggregateProperty.ref().maybeTypes()->clone(GetIonContext()->temp->lifoAlloc());
|
||||
if (!types)
|
||||
return false;
|
||||
|
||||
@ -3085,7 +3097,7 @@ jit::PropertyWriteNeedsTypeBarrier(types::CompilerConstraintList *constraints,
|
||||
|
||||
jsid id = name ? NameToId(name) : JSID_VOID;
|
||||
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
|
||||
// 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
|
||||
@ -3117,10 +3129,10 @@ jit::PropertyWriteNeedsTypeBarrier(types::CompilerConstraintList *constraints,
|
||||
|
||||
jsid id = name ? NameToId(name) : JSID_VOID;
|
||||
types::HeapTypeSetKey property = object->property(id);
|
||||
if (TypeSetIncludes(property.actualTypes, (*pvalue)->type(), (*pvalue)->resultTypeSet()))
|
||||
if (TypeSetIncludes(property.maybeTypes(), (*pvalue)->type(), (*pvalue)->resultTypeSet()))
|
||||
continue;
|
||||
|
||||
if (!property.actualTypes->empty() || excluded)
|
||||
if ((property.maybeTypes() && !property.maybeTypes()->empty()) || excluded)
|
||||
return true;
|
||||
excluded = object->isTypeObject() ? object->asTypeObject() : object->asSingleObject()->getType(GetIonContext()->cx);
|
||||
}
|
||||
|
@ -8993,10 +8993,12 @@ bool ElementAccessIsPacked(types::CompilerConstraintList *constraints, MDefiniti
|
||||
bool ElementAccessHasExtraIndexedProperty(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::StackTypeSet *observed, bool updateObserved);
|
||||
bool PropertyReadNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *constraints,
|
||||
bool PropertyReadNeedsTypeBarrier(JSContext *cx, JSContext *propertycx,
|
||||
types::CompilerConstraintList *constraints,
|
||||
MDefinition *obj, PropertyName *name,
|
||||
types::StackTypeSet *observed);
|
||||
bool PropertyReadOnPrototypeNeedsTypeBarrier(JSContext *cx, types::CompilerConstraintList *constraints,
|
||||
|
@ -336,6 +336,39 @@ TypeSet::isSubset(TypeSet *other)
|
||||
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
|
||||
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
|
||||
* constraint, as doing so may modify this type set.
|
||||
*/
|
||||
Vector<Type> types(cx);
|
||||
|
||||
/* 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);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeList types;
|
||||
if (!enumerateTypes(&types))
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
|
||||
for (unsigned i = 0; i < types.length(); i++)
|
||||
constraint->newType(cx, this, types[i]);
|
||||
@ -566,10 +570,8 @@ class types::CompilerConstraint
|
||||
|
||||
CompilerConstraint(const HeapTypeSetKey &property)
|
||||
: property(property),
|
||||
expected(property.actualTypes->clone(IonAlloc()))
|
||||
{
|
||||
// Note: CompilerConstraintList::add watches for OOM under clone().
|
||||
}
|
||||
expected(property.maybeTypes() ? property.maybeTypes()->clone(IonAlloc()) : NULL)
|
||||
{}
|
||||
|
||||
// Generate the type constraint recording the assumption made by this
|
||||
// compilation. Returns true if the assumption originally made still holds.
|
||||
@ -580,7 +582,7 @@ void
|
||||
CompilerConstraintList::add(CompilerConstraint *constraint)
|
||||
{
|
||||
#ifdef JS_ION
|
||||
if (!constraint || !constraint->expected || !constraints.append(constraint))
|
||||
if (!constraint || !constraints.append(constraint))
|
||||
setFailed();
|
||||
#else
|
||||
MOZ_CRASH();
|
||||
@ -641,14 +643,17 @@ template <typename T>
|
||||
bool
|
||||
CompilerConstraintInstance<T>::generateTypeConstraint(JSContext *cx, RecompileInfo recompileInfo)
|
||||
{
|
||||
if (property.actualObject->unknownProperties())
|
||||
if (property.object()->unknownProperties())
|
||||
return false;
|
||||
|
||||
if (!property.instantiate(cx))
|
||||
return false;
|
||||
|
||||
if (!data.constraintHolds(cx, property, expected))
|
||||
return false;
|
||||
|
||||
property.actualTypes->add(cx, cx->typeLifoAlloc().new_<TypeCompilerConstraint<T> >(recompileInfo, data),
|
||||
/* callExisting = */ false);
|
||||
property.maybeTypes()->add(cx, cx->typeLifoAlloc().new_<TypeCompilerConstraint<T> >(recompileInfo, data),
|
||||
/* callExisting = */ false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -683,37 +688,62 @@ TypeObjectKey::newScript()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TypeObject *
|
||||
TypeObjectKey::maybeType()
|
||||
{
|
||||
if (isTypeObject())
|
||||
return asTypeObject();
|
||||
if (asSingleObject()->hasLazyType())
|
||||
return NULL;
|
||||
return asSingleObject()->type();
|
||||
}
|
||||
|
||||
bool
|
||||
TypeObjectKey::unknownProperties()
|
||||
{
|
||||
#ifdef JS_ION
|
||||
JSContext *cx = jit::GetIonContext()->cx;
|
||||
TypeObject *type = isSingleObject() ? asSingleObject()->getType(cx) : asTypeObject();
|
||||
if (!type)
|
||||
MOZ_CRASH();
|
||||
return type->unknownProperties();
|
||||
#else
|
||||
MOZ_CRASH();
|
||||
#endif
|
||||
if (TypeObject *type = maybeType())
|
||||
return type->unknownProperties();
|
||||
return false;
|
||||
}
|
||||
|
||||
HeapTypeSetKey
|
||||
TypeObjectKey::property(jsid id)
|
||||
TypeObjectKey::property(jsid id, JSContext *maybecx /* = NULL */)
|
||||
{
|
||||
#ifdef JS_ION
|
||||
JSContext *cx = jit::GetIonContext()->cx;
|
||||
TypeObject *type = isSingleObject() ? asSingleObject()->getType(cx) : asTypeObject();
|
||||
if (!type)
|
||||
MOZ_CRASH();
|
||||
JS_ASSERT(!unknownProperties());
|
||||
|
||||
HeapTypeSetKey property;
|
||||
property.actualObject = type;
|
||||
property.actualTypes = type->getProperty(cx, id);
|
||||
if (!property.actualTypes)
|
||||
MOZ_CRASH();
|
||||
property.object_ = this;
|
||||
property.id_ = id;
|
||||
if (TypeObject *type = maybeType())
|
||||
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;
|
||||
#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
|
||||
@ -738,12 +768,17 @@ types::FinishCompilation(JSContext *cx, JSScript *script, ExecutionMode executio
|
||||
|
||||
*precompileInfo = RecompileInfo(index);
|
||||
|
||||
bool succeeded = true;
|
||||
|
||||
for (size_t i = 0; i < constraints->length(); i++) {
|
||||
CompilerConstraint *constraint = constraints->get(i);
|
||||
if (!constraint->generateTypeConstraint(cx, *precompileInfo)) {
|
||||
types.constrainedOutputs->back().invalidate();
|
||||
return false;
|
||||
}
|
||||
if (!constraint->generateTypeConstraint(cx, *precompileInfo))
|
||||
succeeded = false;
|
||||
}
|
||||
|
||||
if (!succeeded) {
|
||||
types.constrainedOutputs->back().invalidate();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -766,7 +801,9 @@ class ConstraintDataFreeze
|
||||
bool constraintHolds(JSContext *cx,
|
||||
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
|
||||
HeapTypeSetKey::knownTypeTag(CompilerConstraintList *constraints)
|
||||
{
|
||||
if (actualTypes->unknown())
|
||||
TypeSet *types = maybeTypes();
|
||||
|
||||
if (!types || types->unknown())
|
||||
return JSVAL_TYPE_UNKNOWN;
|
||||
|
||||
TypeFlags flags = actualTypes->baseFlags() & ~TYPE_FLAG_ANYOBJECT;
|
||||
TypeFlags flags = types->baseFlags() & ~TYPE_FLAG_ANYOBJECT;
|
||||
JSValueType type;
|
||||
|
||||
if (actualTypes->unknownObject() || actualTypes->getObjectCount())
|
||||
if (types->unknownObject() || types->getObjectCount())
|
||||
type = flags ? JSVAL_TYPE_UNKNOWN : JSVAL_TYPE_OBJECT;
|
||||
else
|
||||
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
|
||||
* added to the set.
|
||||
*/
|
||||
JS_ASSERT_IF(actualTypes->empty(), type == JSVAL_TYPE_UNKNOWN);
|
||||
JS_ASSERT_IF(types->empty(), type == JSVAL_TYPE_UNKNOWN);
|
||||
|
||||
return type;
|
||||
}
|
||||
@ -871,7 +910,7 @@ HeapTypeSetKey::knownTypeTag(CompilerConstraintList *constraints)
|
||||
bool
|
||||
HeapTypeSetKey::notEmpty(CompilerConstraintList *constraints)
|
||||
{
|
||||
if (!actualTypes->empty())
|
||||
if (maybeTypes() && !maybeTypes()->empty())
|
||||
return true;
|
||||
freeze(constraints);
|
||||
return false;
|
||||
@ -880,7 +919,11 @@ HeapTypeSetKey::notEmpty(CompilerConstraintList *constraints)
|
||||
bool
|
||||
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;
|
||||
freeze(constraints);
|
||||
return true;
|
||||
@ -898,10 +941,12 @@ TemporaryTypeSet::getSingleton()
|
||||
JSObject *
|
||||
HeapTypeSetKey::singleton(CompilerConstraintList *constraints)
|
||||
{
|
||||
if (actualTypes->baseFlags() != 0 || actualTypes->getObjectCount() != 1)
|
||||
TypeSet *types = maybeTypes();
|
||||
|
||||
if (!types || types->baseFlags() != 0 || types->getObjectCount() != 1)
|
||||
return nullptr;
|
||||
|
||||
JSObject *obj = actualTypes->getSingleObject(0);
|
||||
JSObject *obj = types->getSingleObject(0);
|
||||
|
||||
if (obj)
|
||||
freeze(constraints);
|
||||
@ -912,9 +957,12 @@ HeapTypeSetKey::singleton(CompilerConstraintList *constraints)
|
||||
bool
|
||||
HeapTypeSetKey::needsBarrier(CompilerConstraintList *constraints)
|
||||
{
|
||||
bool result = actualTypes->unknownObject()
|
||||
|| actualTypes->getObjectCount() > 0
|
||||
|| actualTypes->hasAnyFlag(TYPE_FLAG_STRING);
|
||||
TypeSet *types = maybeTypes();
|
||||
if (!types)
|
||||
return false;
|
||||
bool result = types->unknownObject()
|
||||
|| types->getObjectCount() > 0
|
||||
|| types->hasAnyFlag(TYPE_FLAG_STRING);
|
||||
if (!result)
|
||||
freeze(constraints);
|
||||
return result;
|
||||
@ -946,7 +994,7 @@ class ConstraintDataFreezeObjectFlags
|
||||
bool constraintHolds(JSContext *cx,
|
||||
const HeapTypeSetKey &property, TemporaryTypeSet *expected)
|
||||
{
|
||||
return !invalidateOnNewObjectState(property.actualObject);
|
||||
return !invalidateOnNewObjectState(property.object()->maybeType());
|
||||
}
|
||||
};
|
||||
|
||||
@ -955,22 +1003,16 @@ class ConstraintDataFreezeObjectFlags
|
||||
bool
|
||||
TypeObjectKey::hasFlags(CompilerConstraintList *constraints, TypeObjectFlags flags)
|
||||
{
|
||||
#ifdef JS_ION
|
||||
JS_ASSERT(flags);
|
||||
|
||||
JSContext *cx = jit::GetIonContext()->cx;
|
||||
TypeObject *type = isSingleObject() ? asSingleObject()->getType(cx) : asTypeObject();
|
||||
if (!type)
|
||||
MOZ_CRASH();
|
||||
if (type->hasAnyFlags(flags))
|
||||
return true;
|
||||
if (TypeObject *type = maybeType()) {
|
||||
if (type->hasAnyFlags(flags))
|
||||
return true;
|
||||
}
|
||||
|
||||
HeapTypeSetKey objectProperty = property(JSID_EMPTY);
|
||||
constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectFlags> >(objectProperty, ConstraintDataFreezeObjectFlags(flags)));
|
||||
return false;
|
||||
#else
|
||||
MOZ_CRASH();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1047,7 +1089,7 @@ class ConstraintDataFreezeObjectForNewScriptTemplate
|
||||
bool constraintHolds(JSContext *cx,
|
||||
const HeapTypeSetKey &property, TemporaryTypeSet *expected)
|
||||
{
|
||||
return !invalidateOnNewObjectState(property.actualObject);
|
||||
return !invalidateOnNewObjectState(property.object()->maybeType());
|
||||
}
|
||||
};
|
||||
|
||||
@ -1073,7 +1115,7 @@ class ConstraintDataFreezeObjectForTypedArrayBuffer
|
||||
bool constraintHolds(JSContext *cx,
|
||||
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
|
||||
HeapTypeSetKey::configured(CompilerConstraintList *constraints, TypeObjectKey *type)
|
||||
{
|
||||
if (actualTypes->configuredProperty())
|
||||
if (maybeTypes() && maybeTypes()->configuredProperty())
|
||||
return true;
|
||||
|
||||
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
|
||||
// information incorrect), nor for non-array objects (as their elements
|
||||
// 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_)
|
||||
{
|
||||
dontConvert = true;
|
||||
@ -1763,15 +1806,9 @@ bool
|
||||
types::ArrayPrototypeHasIndexedProperty(CompilerConstraintList *constraints,
|
||||
HandleScript script)
|
||||
{
|
||||
#ifdef JS_ION
|
||||
JSObject *proto = script->global().getOrCreateArrayPrototype(jit::GetIonContext()->cx);
|
||||
if (!proto)
|
||||
return true;
|
||||
|
||||
return PrototypeHasIndexedProperty(constraints, proto);
|
||||
#else
|
||||
MOZ_CRASH();
|
||||
#endif
|
||||
if (JSObject *proto = script->global().maybeGetArrayPrototype())
|
||||
return PrototypeHasIndexedProperty(constraints, proto);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -177,8 +177,7 @@ namespace types {
|
||||
|
||||
class TypeCompartment;
|
||||
class TypeSet;
|
||||
|
||||
struct TypeObjectKey;
|
||||
class TypeObjectKey;
|
||||
|
||||
/*
|
||||
* 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. */
|
||||
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
|
||||
* 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;
|
||||
|
||||
/* Type set entry for either a JSObject with singleton type or a non-singleton TypeObject. */
|
||||
struct TypeObjectKey {
|
||||
// Type set entry for either a JSObject with singleton type or a non-singleton TypeObject.
|
||||
struct TypeObjectKey
|
||||
{
|
||||
static intptr_t keyBits(TypeObjectKey *obj) { return (intptr_t) obj; }
|
||||
static TypeObjectKey *getKey(TypeObjectKey *obj) { return obj; }
|
||||
|
||||
@ -1259,14 +1263,40 @@ struct TypeObjectKey {
|
||||
void watchStateChangeForInlinedCall(CompilerConstraintList *constraints);
|
||||
void watchStateChangeForNewScriptTemplate(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
|
||||
{
|
||||
friend class TypeObjectKey;
|
||||
|
||||
// Object and property being accessed.
|
||||
TypeObjectKey *object_;
|
||||
jsid id_;
|
||||
|
||||
// If instantiated, the underlying heap type set.
|
||||
HeapTypeSet *maybeTypes_;
|
||||
|
||||
public:
|
||||
TypeObject *actualObject;
|
||||
HeapTypeSet *actualTypes;
|
||||
HeapTypeSetKey()
|
||||
: 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);
|
||||
JSValueType knownTypeTag(CompilerConstraintList *constraints);
|
||||
|
@ -422,16 +422,19 @@ TrackPropertyTypes(ExclusiveContext *cx, JSObject *obj, jsid id)
|
||||
inline void
|
||||
EnsureTrackPropertyTypes(JSContext *cx, JSObject *obj, jsid id)
|
||||
{
|
||||
JS_ASSERT(!obj->hasLazyType());
|
||||
|
||||
if (!cx->typeInferenceEnabled() || obj->type()->unknownProperties())
|
||||
if (!cx->typeInferenceEnabled())
|
||||
return;
|
||||
|
||||
id = IdToTypeId(id);
|
||||
|
||||
if (obj->hasSingletonType()) {
|
||||
AutoEnterAnalysis enter(cx);
|
||||
obj->type()->getProperty(cx, id);
|
||||
if (obj->hasLazyType() && !obj->getType(cx)) {
|
||||
cx->compartment()->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
if (!obj->type()->unknownProperties())
|
||||
obj->type()->getProperty(cx, id);
|
||||
}
|
||||
|
||||
JS_ASSERT(obj->type()->unknownProperties() || TrackPropertyTypes(cx, obj, id));
|
||||
|
@ -287,6 +287,12 @@ class GlobalObject : public JSObject
|
||||
return &self->getPrototype(JSProto_Array).toObject();
|
||||
}
|
||||
|
||||
JSObject *maybeGetArrayPrototype() {
|
||||
if (arrayClassInitialized())
|
||||
return &getPrototype(JSProto_Array).toObject();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JSObject *getOrCreateBooleanPrototype(JSContext *cx) {
|
||||
if (booleanClassInitialized())
|
||||
return &getPrototype(JSProto_Boolean).toObject();
|
||||
|
Loading…
Reference in New Issue
Block a user