Bug 938124 - Add thread safety class instances to get IonBuilder passing the thread safety dynamic analysis, r=jandem.

This commit is contained in:
Brian Hackett 2013-12-19 10:01:25 -08:00
parent 85defb39cc
commit edafd1dd5b
40 changed files with 436 additions and 161 deletions

View File

@ -1026,6 +1026,8 @@ StructTypeRepresentation::fieldNamed(jsid id) const
uint32_t unused;
JSAtom *atom = JSID_TO_ATOM(id);
AutoThreadSafeAccess ts(atom);
if (atom->isIndex(&unused))
return nullptr;

View File

@ -191,6 +191,9 @@ class BarrieredCell : public gc::Cell
static JS_ALWAYS_INLINE void readBarrier(T *thing) {
#ifdef JSGC_INCREMENTAL
// Off thread Ion compilation never occurs when barriers are active.
js::AutoThreadSafeAccess ts(thing);
JS::shadow::Zone *shadowZone = thing->shadowZoneFromAnyThread();
if (shadowZone->needsBarrier()) {
MOZ_ASSERT(!RuntimeFromMainThreadIsHeapMajorCollecting(shadowZone));

View File

@ -993,12 +993,6 @@ Cell::shadowRuntimeFromAnyThread() const
return reinterpret_cast<JS::shadow::Runtime*>(runtimeFromAnyThread());
}
AllocKind
Cell::tenuredGetAllocKind() const
{
return arenaHeader()->getAllocKind();
}
bool
Cell::isMarked(uint32_t color /* = BLACK */) const
{
@ -1124,7 +1118,9 @@ InFreeList(ArenaHeader *aheader, void *thing)
class AutoThreadSafeAccess
{
public:
#if defined(DEBUG) && !defined(XP_WIN)
#if defined(DEBUG) && defined(JS_CPU_X64) && !defined(XP_WIN)
#define JS_CAN_CHECK_THREADSAFE_ACCESSES
JSRuntime *runtime;
gc::ArenaHeader *arena;
@ -1140,6 +1136,13 @@ public:
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
gc::AllocKind
gc::Cell::tenuredGetAllocKind() const
{
AutoThreadSafeAccess ts(this);
return arenaHeader()->getAllocKind();
}
} /* namespace js */
#endif /* gc_Heap_h */

View File

@ -1132,8 +1132,8 @@ ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type)
if (type->proto().isObject())
PushMarkStack(gcmarker, type->proto().toObject());
if (type->singleton && !type->lazy())
PushMarkStack(gcmarker, type->singleton);
if (type->singleton() && !type->lazy())
PushMarkStack(gcmarker, type->singleton());
if (type->hasNewScript()) {
PushMarkStack(gcmarker, type->newScript()->fun);
@ -1159,8 +1159,8 @@ gc::MarkChildren(JSTracer *trc, types::TypeObject *type)
if (type->proto().isObject())
MarkObject(trc, &type->protoRaw(), "type_proto");
if (type->singleton && !type->lazy())
MarkObject(trc, &type->singleton, "type_singleton");
if (type->singleton() && !type->lazy())
MarkObject(trc, &type->singletonRaw(), "type_singleton");
if (type->hasNewScript()) {
MarkObject(trc, &type->newScript()->fun, "type_new_function");

View File

@ -1,5 +1,9 @@
// |jit-test| error:InternalError
// This test is temporarily disabled in GGC builds (bug 950932).
if (getBuildConfiguration()['generational-gc'])
(function f() { f(); })();
// Binary: cache/js-dbg-64-67bf9a4a1f77-linux
// Flags: --ion-eager
//

View File

@ -1,3 +1,8 @@
// This test is temporarily disabled in GGC builds (bug 950931).
if (getBuildConfiguration()['generational-gc'])
quit();
// The ray tracer code in this file is written by Adam Burmister. It
// is available in its original form from:
//

View File

@ -3393,6 +3393,7 @@ CodeGenerator::visitNewCallObject(LNewCallObject *lir)
Register obj = ToRegister(lir->output());
JSObject *templateObj = lir->mir()->templateObject();
AutoThreadSafeAccess ts(templateObj);
// If we have a template object, we can inline call object creation.
OutOfLineCode *ool;

View File

@ -293,6 +293,8 @@ IonBuilder::getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constr
fun = &obj->as<JSFunction>();
} else {
types::TypeObject *typeObj = calleeTypes->getTypeObject(i);
AutoThreadSafeAccess ts(typeObj);
JS_ASSERT(typeObj);
if (!typeObj->interpretedFunction) {
targets.clear();
@ -395,9 +397,6 @@ IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo)
if (inlineScript->uninlineable())
return DontInline(inlineScript, "Uninlineable script");
if (!inlineScript->analyzedArgsUsage())
return DontInline(inlineScript, "Script without analyzed args usage");
if (inlineScript->needsArgsObj())
return DontInline(inlineScript, "Script that needs an arguments object");
@ -3888,17 +3887,21 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target)
JSScript *calleeScript = target->nonLazyScript();
BaselineInspector inspector(calleeScript);
// Improve type information of |this| when not set.
if (callInfo.constructing() &&
!callInfo.thisArg()->resultTypeSet() &&
calleeScript->types)
{
types::StackTypeSet *types = types::TypeScript::ThisTypes(calleeScript);
if (!types->unknown()) {
MTypeBarrier *barrier =
MTypeBarrier::New(alloc(), callInfo.thisArg(), types->clone(alloc_->lifoAlloc()));
current->add(barrier);
callInfo.setThis(barrier);
AutoThreadSafeAccess ts(calleeScript);
// Improve type information of |this| when not set.
if (callInfo.constructing() &&
!callInfo.thisArg()->resultTypeSet() &&
calleeScript->types)
{
types::StackTypeSet *types = types::TypeScript::ThisTypes(calleeScript);
if (!types->unknown()) {
MTypeBarrier *barrier =
MTypeBarrier::New(alloc(), callInfo.thisArg(), types->clone(alloc_->lifoAlloc()));
current->add(barrier);
callInfo.setThis(barrier);
}
}
}
@ -3930,6 +3933,7 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target)
// Inlining the callee failed. Mark the callee as uninlineable only if
// the inlining was aborted for a non-exception reason.
if (inlineBuilder.abortReason_ == AbortReason_Disable) {
AutoThreadSafeAccess ts(calleeScript);
calleeScript->setUninlineable();
abortReason_ = AbortReason_Inlining;
} else if (inlineBuilder.abortReason_ == AbortReason_Inlining) {
@ -3959,6 +3963,7 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target)
// Accumulate return values.
if (returns.empty()) {
// Inlining of functions that have no exit is not supported.
AutoThreadSafeAccess ts(calleeScript);
calleeScript->setUninlineable();
abortReason_ = AbortReason_Inlining;
return false;
@ -4626,6 +4631,7 @@ IonBuilder::createDeclEnvObject(MDefinition *callee, MDefinition *scope)
// Get a template CallObject that we'll use to generate inline object
// creation.
DeclEnvObject *templateObj = inspector->templateDeclEnvObject();
AutoThreadSafeAccess ts(templateObj);
// One field is added to the function to handle its name. This cannot be a
// dynamic slot because there is still plenty of room on the DeclEnv object.
@ -4653,6 +4659,7 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
// Get a template CallObject that we'll use to generate inline object
// creation.
CallObject *templateObj = inspector->templateCallObject();
AutoThreadSafeAccess ts(templateObj);
// If the CallObject needs dynamic slots, allocate those now.
MInstruction *slots;
@ -4754,10 +4761,13 @@ IonBuilder::createThisScriptedSingleton(JSFunction *target, MDefinition *callee)
if (!templateObject->hasTenuredProto() || templateObject->getProto() != proto)
return nullptr;
if (!target->nonLazyScript()->types)
return nullptr;
if (!types::TypeScript::ThisTypes(target->nonLazyScript())->hasType(types::Type::ObjectType(templateObject)))
return nullptr;
{
AutoThreadSafeAccess ts(target->nonLazyScript());
if (!target->nonLazyScript()->types)
return nullptr;
if (!types::TypeScript::ThisTypes(target->nonLazyScript())->hasType(types::Type::ObjectType(templateObject)))
return nullptr;
}
// For template objects with NewScript info, the appropriate allocation
// kind to use may change due to dynamic property adds. In these cases
@ -5186,6 +5196,9 @@ IonBuilder::testNeedsArgumentCheck(JSFunction *target, CallInfo &callInfo)
return true;
JSScript *targetScript = target->nonLazyScript();
AutoThreadSafeAccess ts(targetScript);
if (!targetScript->types)
return true;
@ -5401,6 +5414,7 @@ IonBuilder::jsop_eval(uint32_t argc)
string->getOperand(1)->toConstant()->value().isString())
{
JSAtom *atom = &string->getOperand(1)->toConstant()->value().toString()->asAtom();
AutoThreadSafeAccess ts(atom);
if (StringEqualsAscii(atom, "()")) {
MDefinition *name = string->getOperand(0);
@ -5476,8 +5490,10 @@ IonBuilder::jsop_newarray(uint32_t count)
types::TemporaryTypeSet::DoubleConversion conversion =
ins->resultTypeSet()->convertDoubleElements(constraints());
if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles) {
AutoThreadSafeAccess ts(templateObject);
templateObject->setShouldConvertDoubleElements();
}
return true;
}
@ -5555,7 +5571,10 @@ IonBuilder::jsop_initelem_array()
MElements *elements = MElements::New(alloc(), obj);
current->add(elements);
if (obj->toNewArray()->templateObject()->shouldConvertDoubleElements()) {
JSObject *templateObject = obj->toNewArray()->templateObject();
AutoThreadSafeAccess ts(templateObject);
if (templateObject->shouldConvertDoubleElements()) {
MInstruction *valueDouble = MToDouble::New(alloc(), value);
current->add(valueDouble);
value = valueDouble;
@ -5584,6 +5603,7 @@ IonBuilder::jsop_initprop(PropertyName *name)
MDefinition *obj = current->peek(-1);
JSObject *templateObject = obj->toNewObject()->templateObject();
AutoThreadSafeAccess ts(templateObject);
Shape *shape = templateObject->lastProperty()->searchLinear(NameToId(name));
@ -9121,6 +9141,9 @@ IonBuilder::jsop_regexp(RegExpObject *reobj)
// then check if this regex object only flows into known natives and can
// avoid cloning in this case.
// RegExpObjects embedded in scripts are immutable.
AutoThreadSafeAccess ts(reobj);
bool mustClone = true;
types::TypeObjectKey *typeObj = types::TypeObjectKey::get(&script()->global());
if (!typeObj->hasFlags(constraints(), types::OBJECT_FLAG_REGEXP_FLAGS_SET)) {

View File

@ -89,6 +89,7 @@ class JitCode : public gc::BarrieredCell<JitCode>
public:
uint8_t *raw() const {
AutoThreadSafeAccess ts(this);
return code_;
}
size_t instructionsSize() const {

View File

@ -787,6 +787,10 @@ MacroAssembler::initGCThing(const Register &obj, JSObject *templateObject)
{
// Fast initialization of an empty object returned by NewGCThing().
AutoThreadSafeAccess ts0(templateObject);
AutoThreadSafeAccess ts1(templateObject->lastProperty());
AutoThreadSafeAccess ts2(templateObject->lastProperty()->base()); // For isNative() assertions.
JS_ASSERT(!templateObject->hasDynamicElements());
storePtr(ImmGCPtr(templateObject->lastProperty()), Address(obj, JSObject::offsetOfShape()));

View File

@ -248,8 +248,10 @@ IonBuilder::inlineArray(CallInfo &callInfo)
types::TemporaryTypeSet::DoubleConversion conversion =
getInlineReturnTypeSet()->convertDoubleElements(constraints());
if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles) {
AutoThreadSafeAccess ts(templateObject);
templateObject->setShouldConvertDoubleElements();
}
MNewArray *ins = MNewArray::New(alloc(), constraints(), initLength, templateObject,
templateObject->type()->initialHeap(constraints()),

View File

@ -669,9 +669,10 @@ MStringLength::foldsTo(TempAllocator &alloc, bool useValueNumbers)
{
if ((type() == MIRType_Int32) && (string()->isConstant())) {
Value value = string()->toConstant()->value();
size_t length = JS_GetStringLength(value.toString());
JSAtom *atom = &value.toString()->asAtom();
return MConstant::New(alloc, Int32Value(length));
AutoThreadSafeAccess ts(atom);
return MConstant::New(alloc, Int32Value(atom->length()));
}
return this;
@ -2512,6 +2513,7 @@ MBeta::printOpcode(FILE *fp) const
bool
MNewObject::shouldUseVM() const
{
AutoThreadSafeAccess ts(templateObject());
return templateObject()->hasSingletonType() ||
templateObject()->hasDynamicSlots();
}

View File

@ -279,6 +279,7 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
#ifdef DEBUG
if (GetIonContext()->cx) {
AutoThreadSafeAccess ts(script);
uint32_t stackDepth;
bool reachablePC;
if (!ReconstructStackDepth(GetIonContext()->cx, script, bailPC, &stackDepth, &reachablePC))

View File

@ -31,6 +31,7 @@ namespace js {
inline jsid
AtomToId(JSAtom *atom)
{
AutoThreadSafeAccess ts(atom);
JS_STATIC_ASSERT(JSID_INT_MIN == 0);
uint32_t index;

View File

@ -29,6 +29,8 @@ BooleanGetPrimitiveValue(HandleObject obj, JSContext *cx)
inline bool
EmulatesUndefined(JSObject *obj)
{
AutoThreadSafeAccess ts0(obj);
AutoThreadSafeAccess ts1(obj->typeRaw());
JSObject *actual = MOZ_LIKELY(!obj->is<WrapperObject>()) ? obj : UncheckedUnwrap(obj);
return actual->getClass()->emulatesUndefined();
}

View File

@ -22,7 +22,14 @@ JSCompartment::initGlobal(js::GlobalObject &global)
js::GlobalObject *
JSCompartment::maybeGlobal() const
{
JS_ASSERT_IF(global_, global_->compartment() == this);
#ifdef DEBUG
if (global_) {
js::AutoThreadSafeAccess ts0(global_);
js::AutoThreadSafeAccess ts1(global_->lastProperty());
js::AutoThreadSafeAccess ts2(global_->lastProperty()->base());
JS_ASSERT(global_->compartment() == this);
}
#endif
return global_;
}

View File

@ -98,7 +98,7 @@ class JSFunction : public JSObject
return false;
// Note: this should be kept in sync with FunctionBox::isHeavyweight().
return nonLazyScript()->bindings.hasAnyAliasedBindings() ||
return nonLazyScript()->hasAnyAliasedBindings() ||
nonLazyScript()->funHasExtensibleScope() ||
nonLazyScript()->funNeedsDeclEnvObject() ||
isGenerator();
@ -176,7 +176,7 @@ class JSFunction : public JSObject
(!isSelfHostedBuiltin() || isSelfHostedConstructor());
}
bool isNamedLambda() const {
return isLambda() && atom_ && !hasGuessedAtom();
return isLambda() && displayAtom() && !hasGuessedAtom();
}
bool hasParallelNative() const {
return isNative() && jitInfo() && !!jitInfo()->parallelNative;
@ -236,7 +236,11 @@ class JSFunction : public JSObject
JSAtom *atom() const { return hasGuessedAtom() ? nullptr : atom_.get(); }
js::PropertyName *name() const { return hasGuessedAtom() || !atom_ ? nullptr : atom_->asPropertyName(); }
void initAtom(JSAtom *atom) { atom_.init(atom); }
JSAtom *displayAtom() const { return atom_; }
JSAtom *displayAtom() const {
js::AutoThreadSafeAccess ts(this);
return atom_;
}
void setGuessedAtom(JSAtom *atom) {
JS_ASSERT(atom_ == nullptr);
@ -254,6 +258,7 @@ class JSFunction : public JSObject
* activations (stack frames) of the function.
*/
JSObject *environment() const {
js::AutoThreadSafeAccess ts(this);
JS_ASSERT(isInterpreted());
return u.i.env_;
}
@ -329,6 +334,7 @@ class JSFunction : public JSObject
}
JSScript *nonLazyScript() const {
js::AutoThreadSafeAccess ts(this);
JS_ASSERT(hasScript());
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
return u.i.s.script_;
@ -340,12 +346,14 @@ class JSFunction : public JSObject
}
js::LazyScript *lazyScript() const {
js::AutoThreadSafeAccess ts(this);
JS_ASSERT(isInterpretedLazy() && u.i.s.lazy_);
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
return u.i.s.lazy_;
}
js::LazyScript *lazyScriptOrNull() const {
js::AutoThreadSafeAccess ts(this);
JS_ASSERT(isInterpretedLazy());
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
return u.i.s.lazy_;
@ -396,6 +404,7 @@ class JSFunction : public JSObject
}
JSNative native() const {
js::AutoThreadSafeAccess ts(this);
JS_ASSERT(isNative());
return u.n.native;
}
@ -420,6 +429,7 @@ class JSFunction : public JSObject
}
const JSJitInfo *jitInfo() const {
js::AutoThreadSafeAccess ts(this);
JS_ASSERT(isNative());
return u.n.jitinfo;
}

View File

@ -686,6 +686,7 @@ TypeScript::FreezeTypeSets(CompilerConstraintList *constraints, JSScript *script
TemporaryTypeSet **pBytecodeTypes)
{
JS_ASSERT(CurrentThreadCanReadCompilationData());
AutoThreadSafeAccess ts(script);
LifoAlloc *alloc = constraints->alloc();
StackTypeSet *existing = script->types->typeArray();
@ -806,6 +807,7 @@ TypeObjectKey::proto()
bool
ObjectImpl::hasTenuredProto() const
{
AutoThreadSafeAccess ts(this);
return type_->hasTenuredProto();
}
@ -818,7 +820,7 @@ TypeObjectKey::hasTenuredProto()
JSObject *
TypeObjectKey::singleton()
{
return isTypeObject() ? asTypeObject()->singleton : asSingleObject();
return isTypeObject() ? asTypeObject()->singleton() : asSingleObject();
}
TypeNewScript *
@ -1386,7 +1388,7 @@ class ConstraintDataFreezeObjectForTypedArrayBuffer
bool invalidateOnNewType(Type type) { return false; }
bool invalidateOnNewPropertyState(TypeSet *property) { return false; }
bool invalidateOnNewObjectState(TypeObject *object) {
return object->singleton->as<TypedArrayObject>().viewData() != viewData;
return object->singleton()->as<TypedArrayObject>().viewData() != viewData;
}
bool constraintHolds(JSContext *cx,
@ -2206,7 +2208,7 @@ TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target)
{
JS_ASSERT(this == &cx->compartment()->types);
JS_ASSERT(!(target->flags() & OBJECT_FLAG_SETS_MARKED_UNKNOWN));
JS_ASSERT(!target->singleton);
JS_ASSERT(!target->singleton());
JS_ASSERT(target->unknownProperties());
AutoEnterAnalysis enter(cx);
@ -2669,10 +2671,10 @@ TypeCompartment::newTypedObject(JSContext *cx, IdValuePair *properties, size_t n
#ifdef DEBUG
void
TypeObject::assertCanAccessProto()
TypeObject::assertCanAccessProto() const
{
// The proto pointer for type objects representing singletons may move.
JS_ASSERT_IF(singleton, CurrentThreadCanReadCompilationData());
JS_ASSERT_IF(singleton(), CurrentThreadCanReadCompilationData());
// Any proto pointer which is in the nursery may be moved, and may not be
// accessed during off thread compilation.
@ -2689,7 +2691,7 @@ void
TypeObject::setProto(JSContext *cx, TaggedProto proto)
{
JS_ASSERT(CurrentThreadCanWriteCompilationData());
JS_ASSERT(singleton);
JS_ASSERT(singleton());
if (proto.isObject() && IsInsideNursery(cx->runtime(), proto.toObject()))
addFlags(OBJECT_FLAG_NURSERY_PROTO);
@ -2737,7 +2739,7 @@ TypeObject::addProperty(ExclusiveContext *cx, jsid id, Property **pprop)
return false;
}
if (singleton && singleton->isNative()) {
if (singleton() && singleton()->isNative()) {
/*
* Fill the property in with any type the object already has in an own
* property. We are only interested in plain native properties and
@ -2745,19 +2747,18 @@ TypeObject::addProperty(ExclusiveContext *cx, jsid id, Property **pprop)
* or jitcode.
*/
RootedObject rSingleton(cx, singleton);
if (JSID_IS_VOID(id)) {
/* Go through all shapes on the object to get integer-valued properties. */
RootedShape shape(cx, singleton->lastProperty());
RootedShape shape(cx, singleton()->lastProperty());
while (!shape->isEmptyShape()) {
if (JSID_IS_VOID(IdToTypeId(shape->propid())))
UpdatePropertyType(cx, &base->types, rSingleton, shape, true);
UpdatePropertyType(cx, &base->types, singleton(), shape, true);
shape = shape->previous();
}
/* Also get values of any dense elements in the object. */
for (size_t i = 0; i < singleton->getDenseInitializedLength(); i++) {
const Value &value = singleton->getDenseElement(i);
for (size_t i = 0; i < singleton()->getDenseInitializedLength(); i++) {
const Value &value = singleton()->getDenseElement(i);
if (!value.isMagic(JS_ELEMENTS_HOLE)) {
Type type = GetValueType(value);
if (!base->types.TypeSet::addType(type, &cx->typeLifoAlloc()))
@ -2766,12 +2767,12 @@ TypeObject::addProperty(ExclusiveContext *cx, jsid id, Property **pprop)
}
} else if (!JSID_IS_EMPTY(id)) {
RootedId rootedId(cx, id);
Shape *shape = singleton->nativeLookup(cx, rootedId);
Shape *shape = singleton()->nativeLookup(cx, rootedId);
if (shape)
UpdatePropertyType(cx, &base->types, rSingleton, shape, false);
UpdatePropertyType(cx, &base->types, singleton(), shape, false);
}
if (singleton->watched()) {
if (singleton()->watched()) {
/*
* Mark the property as configured, to inhibit optimizations on it
* and avoid bypassing the watchpoint handler.
@ -2941,10 +2942,10 @@ TypeObject::setFlags(ExclusiveContext *cx, TypeObjectFlags flags)
AutoEnterAnalysis enter(cx);
if (singleton) {
if (singleton()) {
/* Make sure flags are consistent with persistent object state. */
JS_ASSERT_IF(flags & OBJECT_FLAG_ITERATED,
singleton->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON));
singleton()->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON));
}
{
@ -3761,7 +3762,7 @@ JSObject::makeLazyType(JSContext *cx, HandleObject obj)
/* Fill in the type according to the state of this object. */
type->singleton = obj;
type->initSingleton(obj);
if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted())
type->interpretedFunction = &obj->as<JSFunction>();
@ -3987,7 +3988,7 @@ ExclusiveContext::getLazyType(const Class *clasp, TaggedProto proto)
if (!table.add(p, TypeObjectWithNewScriptEntry(type, nullptr)))
return nullptr;
type->singleton = (JSObject *) TypeObject::LAZY_SINGLETON;
type->initSingleton((JSObject *) TypeObject::LAZY_SINGLETON);
return type;
}
@ -4087,7 +4088,7 @@ TypeObject::sweep(FreeOp *fop)
for (unsigned i = 0; i < oldCapacity; i++) {
Property *prop = oldArray[i];
if (prop) {
if (singleton && !prop->types.constraintList) {
if (singleton() && !prop->types.constraintList) {
/*
* Don't copy over properties of singleton objects which
* don't have associated constraints. The contents of these
@ -4114,7 +4115,7 @@ TypeObject::sweep(FreeOp *fop)
setBasePropertyCount(propertyCount);
} else if (propertyCount == 1) {
Property *prop = (Property *) propertySet;
if (singleton && !prop->types.constraintList) {
if (singleton() && !prop->types.constraintList) {
// Skip, as above.
clearProperties();
} else {
@ -4306,16 +4307,6 @@ TypeCompartment::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t
TypeObject::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
{
if (singleton) {
/*
* Properties and associated type sets for singletons are cleared on
* every GC. The type object is normally destroyed too, but we don't
* charge this to 'temporary' as this is not for GC heap values.
*/
JS_ASSERT(!hasNewScript());
return 0;
}
return mallocSizeOf(addendum);
}

View File

@ -889,51 +889,61 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
HeapPtrObject proto_;
#ifdef DEBUG
void assertCanAccessProto();
void assertCanAccessProto() const;
#else
void assertCanAccessProto() {}
void assertCanAccessProto() const {}
#endif
public:
const Class *clasp() {
return clasp_;
}
void setClasp(const Class *clasp) {
JS_ASSERT(CurrentThreadCanWriteCompilationData());
JS_ASSERT(singleton);
clasp_ = clasp;
}
TaggedProto proto() {
assertCanAccessProto();
return TaggedProto(proto_);
}
HeapPtrObject &protoRaw() {
// For use during marking, don't call otherwise.
return proto_;
}
void setProto(JSContext *cx, TaggedProto proto);
void setProtoUnchecked(TaggedProto proto) {
proto_ = proto.raw();
}
/*
* Whether there is a singleton JS object with this type. That JS object
* must appear in type sets instead of this; we include the back reference
* here to allow reverting the JS object to a lazy type.
*/
HeapPtrObject singleton;
HeapPtrObject singleton_;
public:
const Class *clasp() const {
AutoThreadSafeAccess ts(this);
return clasp_;
}
void setClasp(const Class *clasp) {
JS_ASSERT(CurrentThreadCanWriteCompilationData());
JS_ASSERT(singleton());
clasp_ = clasp;
}
TaggedProto proto() const {
AutoThreadSafeAccess ts(this);
assertCanAccessProto();
return TaggedProto(proto_);
}
JSObject *singleton() const {
AutoThreadSafeAccess ts(this);
return singleton_;
}
// For use during marking, don't call otherwise.
HeapPtrObject &protoRaw() { return proto_; }
HeapPtrObject &singletonRaw() { return singleton_; }
void setProto(JSContext *cx, TaggedProto proto);
void setProtoUnchecked(TaggedProto proto) {
proto_ = proto.raw();
}
void initSingleton(JSObject *singleton) {
singleton_ = singleton;
}
/*
* Value held by singleton if this is a standin type for a singleton JS
* object whose type has not been constructed yet.
*/
static const size_t LAZY_SINGLETON = 1;
bool lazy() const { return singleton == (JSObject *) LAZY_SINGLETON; }
bool lazy() const { return singleton() == (JSObject *) LAZY_SINGLETON; }
private:
/* Flags for this object. */
@ -954,6 +964,7 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
TypeObjectFlags flags() const {
JS_ASSERT(CurrentThreadCanReadCompilationData());
AutoThreadSafeAccess ts(this);
return flags_;
}
@ -969,21 +980,25 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
bool hasNewScript() const {
JS_ASSERT(CurrentThreadCanReadCompilationData());
AutoThreadSafeAccess ts(this);
return addendum && addendum->isNewScript();
}
TypeNewScript *newScript() {
JS_ASSERT(CurrentThreadCanReadCompilationData());
AutoThreadSafeAccess ts(this);
return addendum->asNewScript();
}
bool hasTypedObject() {
JS_ASSERT(CurrentThreadCanReadCompilationData());
AutoThreadSafeAccess ts(this);
return addendum && addendum->isTypedObject();
}
TypeTypedObject *typedObject() {
JS_ASSERT(CurrentThreadCanReadCompilationData());
AutoThreadSafeAccess ts(this);
return addendum->asTypedObject();
}

View File

@ -88,8 +88,9 @@ Type::ObjectType(JSObject *obj)
/* static */ inline Type
Type::ObjectType(TypeObject *obj)
{
if (obj->singleton)
return Type(uintptr_t(obj->singleton.get()) | 1);
AutoThreadSafeAccess ts(obj);
if (obj->singleton())
return Type(uintptr_t(obj->singleton()) | 1);
return Type(uintptr_t(obj));
}
@ -177,8 +178,9 @@ IdToTypeId(jsid id)
* and overflowing integers.
*/
if (JSID_IS_STRING(id)) {
JSFlatString *str = JSID_TO_FLAT_STRING(id);
JS::TwoByteChars cp = str->range();
JSAtom *atom = JSID_TO_ATOM(id);
js::AutoThreadSafeAccess ts(atom);
JS::TwoByteChars cp = atom->range();
if (cp.length() > 0 && (JS7_ISDEC(cp[0]) || cp[0] == '-')) {
for (size_t i = 1; i < cp.length(); ++i) {
if (!JS7_ISDEC(cp[i]))
@ -1085,7 +1087,7 @@ TypeSet::addType(Type type, LifoAlloc *alloc)
if (type.isTypeObject()) {
TypeObject *nobject = type.typeObject();
JS_ASSERT(!nobject->singleton);
JS_ASSERT(!nobject->singleton());
if (nobject->unknownProperties())
goto unknownObject;
}
@ -1317,6 +1319,8 @@ TypeObject::maybeGetProperty(jsid id)
JS_ASSERT(!unknownProperties());
JS_ASSERT(CurrentThreadCanReadCompilationData());
AutoThreadSafeAccess ts(this);
Property *prop = HashSetLookup<jsid,Property,Property>
(propertySet, basePropertyCount(), id);

View File

@ -5506,6 +5506,8 @@ DumpProperty(JSObject *obj, Shape &shape)
bool
JSObject::uninlinedIsProxy() const
{
AutoThreadSafeAccess ts0(this);
AutoThreadSafeAccess ts1(type_);
return is<ProxyObject>();
}

View File

@ -288,6 +288,10 @@ class JSObject : public js::ObjectImpl
}
bool isBoundFunction() const {
// Note: This function can race when it is called during off thread compilation.
js::AutoThreadSafeAccess ts0(this);
js::AutoThreadSafeAccess ts1(lastProperty());
js::AutoThreadSafeAccess ts2(lastProperty()->base());
return lastProperty()->hasObjectFlag(js::BaseShape::BOUND_FUNCTION);
}

View File

@ -3114,12 +3114,14 @@ JSScript::argumentsOptimizationFailed(JSContext *cx, HandleScript script)
bool
JSScript::varIsAliased(unsigned varSlot)
{
AutoThreadSafeAccess ts(this);
return bindings.bindingIsAliased(bindings.numArgs() + varSlot);
}
bool
JSScript::formalIsAliased(unsigned argSlot)
{
AutoThreadSafeAccess ts(this);
return bindings.bindingIsAliased(argSlot);
}

View File

@ -203,11 +203,13 @@ class Bindings
bool bindingArrayUsingTemporaryStorage() const {
return bindingArrayAndFlag_ & TEMPORARY_STORAGE_BIT;
}
public:
Binding *bindingArray() const {
return reinterpret_cast<Binding *>(bindingArrayAndFlag_ & ~TEMPORARY_STORAGE_BIT);
}
public:
inline Bindings();
/*
@ -243,7 +245,14 @@ class Bindings
bool bindingIsAliased(unsigned bindingIndex);
/* Return whether this scope has any aliased bindings. */
bool hasAnyAliasedBindings() const { return callObjShape_ && !callObjShape_->isEmptyShape(); }
bool hasAnyAliasedBindings() const {
if (!callObjShape_)
return false;
// Binding shapes are immutable once constructed.
AutoThreadSafeAccess ts(callObjShape_);
return !callObjShape_->isEmptyShape();
}
void trace(JSTracer *trc);
};
@ -478,6 +487,10 @@ class ScriptSourceObject : public JSObject
const ReadOnlyCompileOptions &options);
ScriptSource *source() {
// Script source objects are immutable.
AutoThreadSafeAccess ts0(this);
AutoThreadSafeAccess ts1(lastProperty());
AutoThreadSafeAccess ts2(lastProperty()->base());
return static_cast<ScriptSource *>(getReservedSlot(SOURCE_SLOT).toPrivate());
}
@ -556,6 +569,26 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
js::Bindings bindings; /* names of top-level variables in this script
(and arguments if this is a function script) */
bool hasAnyAliasedBindings() const {
js::AutoThreadSafeAccess ts(this);
return bindings.hasAnyAliasedBindings();
}
js::Binding *bindingArray() const {
js::AutoThreadSafeAccess ts(this);
return bindings.bindingArray();
}
unsigned numArgs() const {
js::AutoThreadSafeAccess ts(this);
return bindings.numArgs();
}
js::Shape *callObjShape() const {
js::AutoThreadSafeAccess ts(this);
return bindings.callObjShape();
}
// Word-sized fields.
private:
@ -889,12 +922,24 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
bool selfHosted() const { return selfHosted_; }
bool bindingsAccessedDynamically() const { return bindingsAccessedDynamically_; }
bool funHasExtensibleScope() const { return funHasExtensibleScope_; }
bool funNeedsDeclEnvObject() const { return funNeedsDeclEnvObject_; }
bool funHasAnyAliasedFormal() const { return funHasAnyAliasedFormal_; }
bool funHasExtensibleScope() const {
js::AutoThreadSafeAccess ts(this);
return funHasExtensibleScope_;
}
bool funNeedsDeclEnvObject() const {
js::AutoThreadSafeAccess ts(this);
return funNeedsDeclEnvObject_;
}
bool funHasAnyAliasedFormal() const {
js::AutoThreadSafeAccess ts(this);
return funHasAnyAliasedFormal_;
}
bool hasSingletons() const { return hasSingletons_; }
bool treatAsRunOnce() const { return treatAsRunOnce_; }
bool treatAsRunOnce() const {
js::AutoThreadSafeAccess ts(this);
return treatAsRunOnce_;
}
bool hasRunOnce() const { return hasRunOnce_; }
bool hasBeenCloned() const { return hasBeenCloned_; }
@ -921,23 +966,50 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
void setActiveEval() { isActiveEval_ = true; }
void setDirectlyInsideEval() { directlyInsideEval_ = true; }
bool usesArgumentsAndApply() const { return usesArgumentsAndApply_; }
bool usesArgumentsAndApply() const {
js::AutoThreadSafeAccess ts(this);
return usesArgumentsAndApply_;
}
void setUsesArgumentsAndApply() { usesArgumentsAndApply_ = true; }
bool shouldCloneAtCallsite() const { return shouldCloneAtCallsite_; }
bool shouldInline() const { return shouldInline_; }
bool shouldCloneAtCallsite() const {
js::AutoThreadSafeAccess ts(this);
return shouldCloneAtCallsite_;
}
bool shouldInline() const {
js::AutoThreadSafeAccess ts(this);
return shouldInline_;
}
void setShouldCloneAtCallsite() { shouldCloneAtCallsite_ = true; }
void setShouldInline() { shouldInline_ = true; }
bool isCallsiteClone() const { return isCallsiteClone_; }
bool isCallsiteClone() const {
js::AutoThreadSafeAccess ts(this);
return isCallsiteClone_;
}
bool isGeneratorExp() const { return isGeneratorExp_; }
bool failedBoundsCheck() const { return failedBoundsCheck_; }
bool failedShapeGuard() const { return failedShapeGuard_; }
bool hadFrequentBailouts() const { return hadFrequentBailouts_; }
bool uninlineable() const { return uninlineable_; }
bool invalidatedIdempotentCache() const { return invalidatedIdempotentCache_; }
bool failedBoundsCheck() const {
js::AutoThreadSafeAccess ts(this);
return failedBoundsCheck_;
}
bool failedShapeGuard() const {
js::AutoThreadSafeAccess ts(this);
return failedShapeGuard_;
}
bool hadFrequentBailouts() const {
js::AutoThreadSafeAccess ts(this);
return hadFrequentBailouts_;
}
bool uninlineable() const {
js::AutoThreadSafeAccess ts(this);
return uninlineable_;
}
bool invalidatedIdempotentCache() const {
js::AutoThreadSafeAccess ts(this);
return invalidatedIdempotentCache_;
}
void setFailedBoundsCheck() { failedBoundsCheck_ = true; }
void setFailedShapeGuard() { failedShapeGuard_ = true; }
@ -955,7 +1027,10 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
void setWarnedAboutUndefinedProp() { warnedAboutUndefinedProp_ = true; }
/* See ContextFlags::funArgumentsHasLocalBinding comment. */
bool argumentsHasVarBinding() const { return argsHasVarBinding_; }
bool argumentsHasVarBinding() const {
js::AutoThreadSafeAccess ts(this);
return argsHasVarBinding_;
}
jsbytecode *argumentsBytecode() const { JS_ASSERT(code()[0] == JSOP_ARGUMENTS); return code(); }
void setArgumentsHasVarBinding();
bool argumentsAliasesFormals() const {
@ -963,6 +1038,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
}
js::GeneratorKind generatorKind() const {
js::AutoThreadSafeAccess ts(this);
return js::GeneratorKindFromBits(generatorKindBits_);
}
bool isGenerator() const { return generatorKind() != js::NotGenerator; }
@ -987,8 +1063,9 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
*/
bool analyzedArgsUsage() const { return !needsArgsAnalysis_; }
bool needsArgsObj() const {
JS_ASSERT(analyzedArgsUsage());
js::AutoThreadSafeAccess ts(this);
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
JS_ASSERT(analyzedArgsUsage());
return needsArgsObj_;
}
void setNeedsArgsObj(bool needsArgsObj);
@ -1012,9 +1089,11 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
}
bool hasIonScript() const {
js::AutoThreadSafeAccess ts(this);
return ion && ion != ION_DISABLED_SCRIPT && ion != ION_COMPILING_SCRIPT;
}
bool canIonCompile() const {
js::AutoThreadSafeAccess ts(this);
return ion != ION_DISABLED_SCRIPT;
}
@ -1041,6 +1120,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
bool hasBaselineScript() const {
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
js::AutoThreadSafeAccess ts(this);
return baseline && baseline != BASELINE_DISABLED_SCRIPT;
}
bool canBaselineCompile() const {
@ -1048,6 +1128,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
}
js::jit::BaselineScript *baselineScript() const {
JS_ASSERT(hasBaselineScript());
js::AutoThreadSafeAccess ts(this);
return baseline;
}
inline void setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselineScript);
@ -1059,6 +1140,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
}
bool canParallelIonCompile() const {
js::AutoThreadSafeAccess ts(this);
return parallelIon != ION_DISABLED_SCRIPT;
}
@ -1099,7 +1181,10 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
* Original compiled function for the script, if it has a function.
* nullptr for global and eval scripts.
*/
JSFunction *function() const { return function_; }
JSFunction *function() const {
js::AutoThreadSafeAccess ts(this);
return function_;
}
inline void setFunction(JSFunction *fun);
JSFunction *originalFunction() const;
@ -1110,7 +1195,10 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
static bool loadSource(JSContext *cx, js::ScriptSource *ss, bool *worked);
void setSourceObject(JSObject *object);
JSObject *sourceObject() const { return sourceObject_; }
JSObject *sourceObject() const {
js::AutoThreadSafeAccess ts(this);
return sourceObject_;
}
js::ScriptSource *scriptSource() const;
JSPrincipals *originPrincipals() const { return scriptSource()->originPrincipals(); }
const char *filename() const { return scriptSource()->filename(); }
@ -1149,6 +1237,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
JSObject *enclosingStaticScope() const {
if (isCallsiteClone())
return nullptr;
js::AutoThreadSafeAccess ts(this);
return enclosingScopeOrOriginalFunction_;
}
@ -1169,7 +1258,11 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
bool makeAnalysis(JSContext *cx);
public:
uint32_t getUseCount() const { return useCount; }
uint32_t getUseCount() const {
// Note: We ignore races when reading the use count of a script off thread.
js::AutoThreadSafeAccess ts(this);
return useCount;
}
uint32_t incUseCount(uint32_t amount = 1) { return useCount += amount; }
uint32_t *addressOfUseCount() { return &useCount; }
static size_t offsetOfUseCount() { return offsetof(JSScript, useCount); }
@ -1201,8 +1294,11 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
/* Script notes are allocated right after the code. */
jssrcnote *notes() { return (jssrcnote *)(code() + length()); }
bool hasArray(ArrayKind kind) { return (hasArrayBits & (1 << kind)); }
void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); }
bool hasArray(ArrayKind kind) {
js::AutoThreadSafeAccess ts(this);
return (hasArrayBits & (1 << kind));
}
void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); }
void cloneHasArray(JSScript *script) { hasArrayBits = script->hasArrayBits; }
bool hasConsts() { return hasArray(CONSTS); }
@ -1223,26 +1319,31 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
js::ConstArray *consts() {
JS_ASSERT(hasConsts());
js::AutoThreadSafeAccess ts(this);
return reinterpret_cast<js::ConstArray *>(data + constsOffset());
}
js::ObjectArray *objects() {
JS_ASSERT(hasObjects());
js::AutoThreadSafeAccess ts(this);
return reinterpret_cast<js::ObjectArray *>(data + objectsOffset());
}
js::ObjectArray *regexps() {
JS_ASSERT(hasRegexps());
js::AutoThreadSafeAccess ts(this);
return reinterpret_cast<js::ObjectArray *>(data + regexpsOffset());
}
js::TryNoteArray *trynotes() {
JS_ASSERT(hasTrynotes());
js::AutoThreadSafeAccess ts(this);
return reinterpret_cast<js::TryNoteArray *>(data + trynotesOffset());
}
js::BlockScopeArray *blockScopes() {
JS_ASSERT(hasBlockScopes());
js::AutoThreadSafeAccess ts(this);
return reinterpret_cast<js::BlockScopeArray *>(data + blockScopesOffset());
}
@ -1251,6 +1352,7 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
size_t natoms() const { return natoms_; }
js::HeapPtrAtom &getAtom(size_t index) const {
js::AutoThreadSafeAccess ts(this);
JS_ASSERT(index < natoms());
return atoms[index];
}
@ -1604,6 +1706,7 @@ class LazyScript : public gc::BarrieredCell<LazyScript>
}
bool usesArgumentsAndApply() const {
AutoThreadSafeAccess ts(this);
return usesArgumentsAndApply_;
}
void setUsesArgumentsAndApply() {
@ -1628,9 +1731,11 @@ class LazyScript : public gc::BarrieredCell<LazyScript>
return sourceObject()->source();
}
uint32_t begin() const {
AutoThreadSafeAccess ts(this);
return begin_;
}
uint32_t end() const {
AutoThreadSafeAccess ts(this);
return end_;
}
uint32_t lineno() const {

View File

@ -26,9 +26,9 @@ Bindings::Bindings()
inline
AliasedFormalIter::AliasedFormalIter(JSScript *script)
: begin_(script->bindings.bindingArray()),
: begin_(script->bindingArray()),
p_(begin_),
end_(begin_ + (script->funHasAnyAliasedFormal() ? script->bindings.numArgs() : 0)),
end_(begin_ + (script->funHasAnyAliasedFormal() ? script->numArgs() : 0)),
slot_(CallObject::RESERVED_SLOTS)
{
settle();
@ -98,6 +98,7 @@ JSScript::global() const
* A JSScript always marks its compartment's global (via bindings) so we
* can assert that maybeGlobal is non-null here.
*/
js::AutoThreadSafeAccess ts(this);
return *compartment()->maybeGlobal();
}

View File

@ -4142,6 +4142,8 @@ js::CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *resul
int32_t
js::CompareAtoms(JSAtom *atom1, JSAtom *atom2)
{
AutoThreadSafeAccess ts0(atom1);
AutoThreadSafeAccess ts1(atom2);
return CompareChars(atom1->chars(), atom1->length(), atom2->chars(), atom2->length());
}

View File

@ -77,8 +77,15 @@ JS_FRIEND_API(JSObject *)
js::UncheckedUnwrap(JSObject *wrapped, bool stopAtOuter, unsigned *flagsp)
{
unsigned flags = 0;
while (wrapped->is<WrapperObject>() &&
!JS_UNLIKELY(stopAtOuter && wrapped->getClass()->ext.innerObject)) {
while (true) {
AutoThreadSafeAccess ts0(wrapped);
AutoThreadSafeAccess ts1(wrapped->typeRaw());
AutoThreadSafeAccess ts2(wrapped->lastProperty());
if (!wrapped->is<WrapperObject>() ||
JS_UNLIKELY(stopAtOuter && wrapped->getClass()->ext.innerObject))
{
break;
}
flags |= Wrapper::wrapperHandler(wrapped)->flags();
wrapped = wrapped->as<ProxyObject>().private_().toObjectOrNull();
}

View File

@ -452,15 +452,15 @@ GlobalObject::getOrCreateEval(JSContext *cx, Handle<GlobalObject*> global,
{
if (!global->getOrCreateObjectPrototype(cx))
return false;
eval.set(&global->getSlotRefForCompilation(EVAL).toObject());
eval.set(&global->getSlotForCompilation(EVAL).toObject());
return true;
}
bool
GlobalObject::valueIsEval(Value val)
{
HeapSlot &eval = getSlotRef(EVAL);
return eval.isObject() && eval.get() == val;
Value eval = getSlotForCompilation(EVAL);
return eval.isObject() && eval == val;
}
/* static */ bool

View File

@ -155,7 +155,7 @@ class GlobalObject : public JSObject
public:
Value getConstructor(JSProtoKey key) const {
JS_ASSERT(key <= JSProto_LIMIT);
return getSlotRefForCompilation(APPLICATION_SLOTS + key);
return getSlotForCompilation(APPLICATION_SLOTS + key);
}
void setConstructor(JSProtoKey key, const Value &v) {
@ -165,7 +165,7 @@ class GlobalObject : public JSObject
Value getPrototype(JSProtoKey key) const {
JS_ASSERT(key <= JSProto_LIMIT);
return getSlotRefForCompilation(APPLICATION_SLOTS + JSProto_LIMIT + key);
return getSlotForCompilation(APPLICATION_SLOTS + JSProto_LIMIT + key);
}
void setPrototype(JSProtoKey key, const Value &value) {
@ -447,13 +447,14 @@ class GlobalObject : public JSObject
return &self->getSlot(slot).toObject();
}
const HeapSlot &getSlotRefForCompilation(uint32_t slot) const {
Value getSlotForCompilation(uint32_t slot) const {
// This method should only be used for slots that are either eagerly
// initialized on creation of the global or only change under the
// compilation lock. Note that the dynamic slots pointer for global
// objects can only change under the compilation lock.
JS_ASSERT(slot < JSCLASS_RESERVED_SLOTS(getClass()));
uint32_t fixed = numFixedSlotsForCompilation();
AutoThreadSafeAccess ts(this);
if (slot < fixed)
return fixedSlots()[slot];
return slots[slot - fixed];
@ -509,13 +510,18 @@ class GlobalObject : public JSObject
}
JSObject *intrinsicsHolder() {
JS_ASSERT(!getSlotRefForCompilation(INTRINSICS).isUndefined());
return &getSlotRefForCompilation(INTRINSICS).toObject();
JS_ASSERT(!getSlotForCompilation(INTRINSICS).isUndefined());
return &getSlotForCompilation(INTRINSICS).toObject();
}
bool maybeGetIntrinsicValue(jsid id, Value *vp) {
JS_ASSERT(CurrentThreadCanReadCompilationData());
JSObject *holder = intrinsicsHolder();
AutoThreadSafeAccess ts0(holder);
AutoThreadSafeAccess ts1(holder->lastProperty());
AutoThreadSafeAccess ts2(holder->lastProperty()->base());
if (Shape *shape = holder->nativeLookupPure(id)) {
*vp = holder->getSlot(shape->slot());
return true;
@ -553,7 +559,8 @@ class GlobalObject : public JSObject
unsigned nargs, MutableHandleValue funVal);
RegExpStatics *getRegExpStatics() const {
JSObject &resObj = getSlotRefForCompilation(REGEXP_STATICS).toObject();
JSObject &resObj = getSlotForCompilation(REGEXP_STATICS).toObject();
AutoThreadSafeAccess ts(&resObj);
return static_cast<RegExpStatics *>(resObj.getPrivate(/* nfixed = */ 1));
}

View File

@ -980,13 +980,15 @@ class ObjectImpl : public gc::BarrieredCell<ObjectImpl>
/* These functions are public, and they should remain public. */
public:
js::TaggedProto getTaggedProto() const {
TaggedProto getTaggedProto() const {
AutoThreadSafeAccess ts(this);
return type_->proto();
}
bool hasTenuredProto() const;
const Class *getClass() const {
AutoThreadSafeAccess ts(this);
return type_->clasp();
}
@ -1193,6 +1195,12 @@ class ObjectImpl : public gc::BarrieredCell<ObjectImpl>
types::TypeObject *type() const {
MOZ_ASSERT(!hasLazyType());
return typeRaw();
}
types::TypeObject *typeRaw() const {
AutoThreadSafeAccess ts0(this);
AutoThreadSafeAccess ts1(type_);
return type_;
}
@ -1206,13 +1214,19 @@ class ObjectImpl : public gc::BarrieredCell<ObjectImpl>
* Whether this is the only object which has its specified type. This
* object will have its type constructed lazily as needed by analysis.
*/
bool hasSingletonType() const { return !!type_->singleton; }
bool hasSingletonType() const {
AutoThreadSafeAccess ts(this);
return !!type_->singleton();
}
/*
* Whether the object's type has not been constructed yet. If an object
* might have a lazy type, use getType() below, otherwise type().
*/
bool hasLazyType() const { return type_->lazy(); }
bool hasLazyType() const {
AutoThreadSafeAccess ts(this);
return type_->lazy();
}
uint32_t slotSpan() const {
if (inDictionaryMode())
@ -1540,6 +1554,10 @@ JS_ALWAYS_INLINE Zone *
BarrieredCell<ObjectImpl>::zoneFromAnyThread() const
{
const ObjectImpl* obj = static_cast<const ObjectImpl*>(this);
// Note: This read of obj->shape_ may race, though the zone fetched will be the same.
AutoThreadSafeAccess ts(obj->shape_);
return obj->shape_->zoneFromAnyThread();
}

View File

@ -47,7 +47,12 @@ NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entry_, js::gc::Initi
Entry *entry = &entries[entry_];
JSObject *templateObj = reinterpret_cast<JSObject *>(&entry->templateObject);
if (templateObj->type()->shouldPreTenure())
// Do an end run around JSObject::type() to avoid doing AutoUnprotectCell
// on the templateObj, which is not a GC thing and can't use runtimeFromAnyThread.
types::TypeObject *type = templateObj->type_;
if (type->shouldPreTenure())
heap = gc::TenuredHeap;
JSObject *obj = js_NewGCObject<NoGC>(cx, entry->kind, heap);

View File

@ -15,7 +15,7 @@
#include <locale.h>
#include <string.h>
#if defined(DEBUG) && !defined(XP_WIN)
#ifdef JS_CAN_CHECK_THREADSAFE_ACCESSES
# include <sys/mman.h>
#endif
@ -853,7 +853,7 @@ JSRuntime::activeGCInAtomsZone()
return zone->needsBarrier() || zone->isGCScheduled() || zone->wasGCStarted();
}
#if defined(DEBUG) && !defined(XP_WIN)
#ifdef JS_CAN_CHECK_THREADSAFE_ACCESSES
AutoProtectHeapForIonCompilation::AutoProtectHeapForIonCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
: runtime(rt)
@ -902,7 +902,7 @@ AutoThreadSafeAccess::AutoThreadSafeAccess(const Cell *cell MOZ_GUARD_OBJECT_NOT
arena = base;
if (mprotect(arena, sizeof(Arena), PROT_READ))
if (mprotect(arena, sizeof(Arena), PROT_READ | PROT_WRITE))
MOZ_CRASH();
if (!runtime->unprotectedArenas.append(arena))
@ -921,7 +921,7 @@ AutoThreadSafeAccess::~AutoThreadSafeAccess()
runtime->unprotectedArenas.popBack();
}
#endif // DEBUG && !XP_WIN
#endif // JS_CAN_CHECK_THREADSAFE_ACCESSES
#ifdef JS_WORKER_THREADS

View File

@ -2140,7 +2140,7 @@ class AutoEnterIonCompilation
class AutoProtectHeapForIonCompilation
{
public:
#if defined(DEBUG) && !defined(XP_WIN)
#ifdef JS_CAN_CHECK_THREADSAFE_ACCESSES
JSRuntime *runtime;
AutoProtectHeapForIonCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM);

View File

@ -75,9 +75,11 @@ StaticScopeIter<allowGC>::scopeShape() const
{
JS_ASSERT(hasDynamicScopeObject());
JS_ASSERT(type() != NAMED_LAMBDA);
return type() == BLOCK
? block().lastProperty()
: funScript()->bindings.callObjShape();
if (type() == BLOCK) {
AutoThreadSafeAccess ts(&block());
return block().lastProperty();
}
return funScript()->callObjShape();
}
template <AllowGC allowGC>

View File

@ -99,7 +99,7 @@ js::ScopeCoordinateName(ScopeCoordinateNameCache &cache, JSScript *script, jsbyt
Shape::Range<NoGC> r(shape);
while (r.front().slot() != sc.slot)
r.popFront();
id = r.front().propid();
id = r.front().propidRaw();
}
/* Beware nameless destructuring formal. */

View File

@ -181,6 +181,7 @@ class ScopeObject : public JSObject
* enclosing scope of a ScopeObject is necessarily non-null.
*/
inline JSObject &enclosingScope() const {
AutoThreadSafeAccess ts(this);
return getFixedSlot(SCOPE_CHAIN_SLOT).toObject();
}
@ -232,6 +233,7 @@ class CallObject : public ScopeObject
/* True if this is for a strict mode eval frame. */
bool isForEval() const {
AutoThreadSafeAccess ts(this);
JS_ASSERT(getFixedSlot(CALLEE_SLOT).isObjectOrNull());
JS_ASSERT_IF(getFixedSlot(CALLEE_SLOT).isObject(),
getFixedSlot(CALLEE_SLOT).toObject().is<JSFunction>());
@ -243,6 +245,7 @@ class CallObject : public ScopeObject
* only be called if !isForEval.)
*/
JSFunction &callee() const {
AutoThreadSafeAccess ts(this);
return getFixedSlot(CALLEE_SLOT).toObject().as<JSFunction>();
}
@ -368,6 +371,7 @@ class StaticBlockObject : public BlockObject
/* See StaticScopeIter comment. */
JSObject *enclosingStaticScope() const {
AutoThreadSafeAccess ts(this);
return getFixedSlot(SCOPE_CHAIN_SLOT).toObjectOrNull();
}
@ -400,6 +404,7 @@ class StaticBlockObject : public BlockObject
bool needsClone() {
// The first variable slot will always indicate whether the object has
// any aliased vars. Bypass slotValue() to allow testing this off thread.
AutoThreadSafeAccess ts(this);
return !getFixedSlot(RESERVED_SLOTS).isFalse();
}

View File

@ -195,7 +195,7 @@ ShapeTable::search(jsid id, bool adding)
/* Hit: return entry. */
shape = SHAPE_CLEAR_COLLISION(stored);
if (shape && shape->propid() == id)
if (shape && shape->propidRaw() == id)
return spp;
/* Collision: double hash. */
@ -229,7 +229,7 @@ ShapeTable::search(jsid id, bool adding)
return (adding && firstRemoved) ? firstRemoved : spp;
shape = SHAPE_CLEAR_COLLISION(stored);
if (shape && shape->propid() == id) {
if (shape && shape->propidRaw() == id) {
JS_ASSERT(collision_flag);
return spp;
}

View File

@ -1034,11 +1034,15 @@ class Shape : public gc::BarrieredCell<Shape>
void popFront() {
JS_ASSERT(!empty());
AutoThreadSafeAccess ts(cursor);
cursor = cursor->parent;
}
};
const Class *getObjectClass() const { return base()->clasp; }
const Class *getObjectClass() const {
AutoThreadSafeAccess ts(base());
return base()->clasp;
}
JSObject *getObjectParent() const { return base()->parent; }
JSObject *getObjectMetadata() const { return base()->metadata; }
@ -1095,12 +1099,15 @@ class Shape : public gc::BarrieredCell<Shape>
PUBLIC_FLAGS = HAS_SHORTID
};
bool inDictionary() const { return (flags & IN_DICTIONARY) != 0; }
unsigned getFlags() const { return flags & PUBLIC_FLAGS; }
bool inDictionary() const {
AutoThreadSafeAccess ts(this);
return (flags & IN_DICTIONARY) != 0;
}
unsigned getFlags() const { return flags & PUBLIC_FLAGS; }
bool hasShortID() const { return (flags & HAS_SHORTID) != 0; }
PropertyOp getter() const { return base()->rawGetter; }
bool hasDefaultGetter() const { return !base()->rawGetter; }
bool hasDefaultGetter() const {return !base()->rawGetter; }
PropertyOp getterOp() const { JS_ASSERT(!hasGetterValue()); return base()->rawGetter; }
JSObject *getterObject() const { JS_ASSERT(hasGetterValue()); return base()->getterObj; }
@ -1158,11 +1165,21 @@ class Shape : public gc::BarrieredCell<Shape>
BaseShape *base() const { return base_.get(); }
bool hasSlot() const { return (attrs & JSPROP_SHARED) == 0; }
bool hasSlot() const {
AutoThreadSafeAccess ts(this);
return (attrs & JSPROP_SHARED) == 0;
}
uint32_t slot() const { JS_ASSERT(hasSlot() && !hasMissingSlot()); return maybeSlot(); }
uint32_t maybeSlot() const { return slotInfo & SLOT_MASK; }
uint32_t maybeSlot() const {
// Note: Reading a shape's slot off thread can race against main thread
// updates to the number of linear searches on the shape, which is
// stored in the same slotInfo field. We tolerate this.
AutoThreadSafeAccess ts(this);
return slotInfo & SLOT_MASK;
}
bool isEmptyShape() const {
AutoThreadSafeAccess ts(this);
JS_ASSERT_IF(JSID_IS_EMPTY(propid_), hasMissingSlot());
return JSID_IS_EMPTY(propid_);
}
@ -1184,6 +1201,8 @@ class Shape : public gc::BarrieredCell<Shape>
}
uint32_t numFixedSlots() const {
// Note: The same race applies here as in maybeSlot().
AutoThreadSafeAccess ts(this);
return (slotInfo >> FIXED_SLOTS_SHIFT);
}
@ -1205,11 +1224,17 @@ class Shape : public gc::BarrieredCell<Shape>
}
const EncapsulatedId &propid() const {
AutoThreadSafeAccess ts(this);
JS_ASSERT(!isEmptyShape());
JS_ASSERT(!JSID_IS_VOID(propid_));
return propid_;
}
EncapsulatedId &propidRef() { JS_ASSERT(!JSID_IS_VOID(propid_)); return propid_; }
jsid propidRaw() const {
// Return the actual jsid, not an internal reference.
AutoThreadSafeAccess ts(this);
return propid();
}
int16_t shortid() const { JS_ASSERT(hasShortID()); return maybeShortid(); }
int16_t maybeShortid() const { return shortid_; }
@ -1225,6 +1250,7 @@ class Shape : public gc::BarrieredCell<Shape>
bool enumerable() const { return (attrs & JSPROP_ENUMERATE) != 0; }
bool writable() const {
// JS_ASSERT(isDataDescriptor());
AutoThreadSafeAccess ts(this);
return (attrs & JSPROP_READONLY) == 0;
}
bool hasGetterValue() const { return attrs & JSPROP_GETTER; }
@ -1616,9 +1642,11 @@ Shape::searchLinear(jsid id)
*/
JS_ASSERT(!inDictionary());
for (Shape *shape = this; shape; shape = shape->parent) {
for (Shape *shape = this; shape; ) {
AutoThreadSafeAccess ts(shape);
if (shape->propidRef() == id)
return shape;
shape = shape->parent;
}
return nullptr;

View File

@ -394,6 +394,7 @@ class JSString : public js::gc::BarrieredCell<JSString>
JS_ALWAYS_INLINE
JSAtom &asAtom() const {
js::AutoThreadSafeAccess ts(this);
JS_ASSERT(isAtom());
return *(JSAtom *)this;
}
@ -1129,6 +1130,7 @@ JSString::base() const
inline js::PropertyName *
JSAtom::asPropertyName()
{
js::AutoThreadSafeAccess ts(this);
#ifdef DEBUG
uint32_t dummy;
JS_ASSERT(!isIndex(&dummy));

View File

@ -324,9 +324,11 @@ class TypedArrayObject : public ArrayBufferViewObject
return tarr->getFixedSlot(BYTEOFFSET_SLOT);
}
static Value byteLengthValue(TypedArrayObject *tarr) {
AutoThreadSafeAccess ts(tarr);
return tarr->getFixedSlot(BYTELENGTH_SLOT);
}
static Value lengthValue(TypedArrayObject *tarr) {
AutoThreadSafeAccess ts(tarr);
return tarr->getFixedSlot(LENGTH_SLOT);
}
@ -344,9 +346,11 @@ class TypedArrayObject : public ArrayBufferViewObject
}
uint32_t type() const {
AutoThreadSafeAccess ts(this);
return getFixedSlot(TYPE_SLOT).toInt32();
}
void *viewData() const {
AutoThreadSafeAccess ts(this);
return static_cast<void*>(getPrivate(DATA_SLOT));
}