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;
|
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,
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user