diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 8bbc20e1d9f..b5e029724d8 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -4497,8 +4497,7 @@ EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) */ if (fun->isInterpreted()) { bool singleton = - cx->isJSContext() && - cx->asJSContext()->typeInferenceEnabled() && + cx->typeInferenceEnabled() && bce->script->compileAndGo && fun->isInterpreted() && (bce->checkSingletonContext() || diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 0745e5b6cc6..40067ff6731 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -820,7 +820,7 @@ IonBuilder::initParameters() types::StackTypeSet *thisTypes = types::TypeScript::ThisTypes(script()); if (thisTypes->empty() && baselineFrame_) - thisTypes->addType(cx, types::GetValueType(cx, baselineFrame_->thisValue())); + thisTypes->addType(cx, types::GetValueType(baselineFrame_->thisValue())); MParameter *param = MParameter::New(MParameter::THIS_SLOT, cloneTypeSet(thisTypes)); current->add(param); @@ -831,7 +831,7 @@ IonBuilder::initParameters() if (argTypes->empty() && baselineFrame_ && !script_->baselineScript()->modifiesArguments()) { - argTypes->addType(cx, types::GetValueType(cx, baselineFrame_->argv()[i])); + argTypes->addType(cx, types::GetValueType(baselineFrame_->argv()[i])); } param = MParameter::New(i, cloneTypeSet(argTypes)); @@ -5773,7 +5773,7 @@ IonBuilder::newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc, bool MIRType type = existingValue.isDouble() ? MIRType_Double : MIRTypeFromValueType(existingValue.extractNonDoubleType()); - types::Type ntype = types::GetValueType(cx, existingValue); + types::Type ntype = types::GetValueType(existingValue); types::StackTypeSet *typeSet = GetIonContext()->temp->lifoAlloc()->new_(ntype); phi->addBackedgeType(type, typeSet); @@ -6363,7 +6363,7 @@ IonBuilder::jsop_intrinsic(HandlePropertyName name) if (!cx->global()->getIntrinsicValue(cx, name, &vp)) return false; - JS_ASSERT(types->hasType(types::GetValueType(cx, vp))); + JS_ASSERT(types->hasType(types::GetValueType(vp))); MConstant *ins = MConstant::New(vp); current->add(ins); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 42a1c9d2058..cdc0231ca7a 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -2546,7 +2546,7 @@ ion::PropertyReadNeedsTypeBarrier(JSContext *cx, types::TypeObject *object, Prop if (HasDataProperty(cx, obj, id, &v)) { if (v.isUndefined()) break; - observed->addType(cx, types::GetValueType(cx, v)); + observed->addType(cx, types::GetValueType(v)); } obj = obj->getProto(); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 02e650a38e1..b2a2e1aa43c 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1075,7 +1075,7 @@ InitArrayTypes(JSContext *cx, TypeObject *type, const Value *vector, unsigned co for (unsigned i = 0; i < count; i++) { if (vector[i].isMagic(JS_ELEMENTS_HOLE)) continue; - Type valtype = GetValueType(cx, vector[i]); + Type valtype = GetValueType(vector[i]); types->addType(cx, valtype); } } diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 40a1fad3927..2c7bd202cdd 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -259,10 +259,11 @@ struct ThreadSafeContext : ContextFriendFields, js_ReportAllocationOverflow(this); } - // Builtin atoms are immutable and may be accessed freely from any thread. + // Accessors for immutable runtime data. JSAtomState &names() { return runtime_->atomState; } StaticStrings &staticStrings() { return runtime_->staticStrings; } PropertyName *emptyString() { return runtime_->emptyString; } + FreeOp *defaultFreeOp() { return runtime_->defaultFreeOp(); } // GCs cannot happen while non-main threads are running. uint64_t gcNumber() { return runtime_->gcNumber; } @@ -351,6 +352,7 @@ class ExclusiveContext : public ThreadSafeContext // Zone local methods that can be used freely from an ExclusiveContext. inline bool typeInferenceEnabled() const; types::TypeObject *getNewType(Class *clasp, TaggedProto proto, JSFunction *fun = NULL); + inline js::LifoAlloc &typeLifoAlloc(); // Current global. This is only safe to use within the scope of the // AutoCompartment from which it's called. @@ -483,7 +485,6 @@ struct JSContext : public js::ExclusiveContext, js::LifoAlloc &tempLifoAlloc() { return runtime()->tempLifoAlloc; } inline js::LifoAlloc &analysisLifoAlloc(); - inline js::LifoAlloc &typeLifoAlloc(); #ifdef JS_THREADSAFE unsigned outstandingRequests;/* number of JS_BeginRequest calls diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index eb5030185a0..ec1c308f46b 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -406,6 +406,12 @@ class AutoLockForExclusiveAccess MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; +inline LifoAlloc & +ExclusiveContext::typeLifoAlloc() +{ + return zone()->types.typeLifoAlloc; +} + } /* namespace js */ inline js::LifoAlloc & @@ -414,12 +420,6 @@ JSContext::analysisLifoAlloc() return compartment()->analysisLifoAlloc; } -inline js::LifoAlloc & -JSContext::typeLifoAlloc() -{ - return zone()->types.typeLifoAlloc; -} - inline void JSContext::setPendingException(js::Value v) { JS_ASSERT(!IsPoisonedValue(v)); diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index d01ee66ac6c..21bea397d51 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -433,10 +433,6 @@ namespace js { inline bool ExclusiveContext::typeInferenceEnabled() const { - // Type inference cannot be enabled in compartments which are accessed off - // the main thread by an ExclusiveContext. TI data is stored in per-zone - // allocators which could otherwise race with main thread operations. - JS_ASSERT_IF(!isJSContext(), !compartment_->zone()->types.inferenceEnabled); return compartment_->zone()->types.inferenceEnabled; } diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 26dd00fe2a7..c03c06db796 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -4055,6 +4055,13 @@ AutoGCSession::AutoGCSession(JSRuntime *rt) runtime->gcInterFrameGC = true; runtime->gcNumber++; + +#ifdef DEBUG + // Threads with an exclusive context should never pause while they are in + // the middle of a suppressGC. + for (ThreadDataIter iter(rt); !iter.done(); iter.next()) + JS_ASSERT(!iter->suppressGC); +#endif } AutoGCSession::~AutoGCSession() @@ -4816,6 +4823,9 @@ gc::MergeCompartments(JSCompartment *source, JSCompartment *target) target->zone()->allocator.arenas.adoptArenas(rt, &source->zone()->allocator.arenas); target->zone()->gcBytes += source->zone()->gcBytes; source->zone()->gcBytes = 0; + + // Merge other info in source's zone into target's zone. + target->zone()->types.typeLifoAlloc.transferFrom(&source->zone()->types.typeLifoAlloc); } void @@ -5140,8 +5150,8 @@ AutoMaybeTouchDeadZones::~AutoMaybeTouchDeadZones() runtime->gcManipulatingDeadZones = manipulatingDeadZones; } -AutoSuppressGC::AutoSuppressGC(JSContext *cx) - : suppressGC_(cx->runtime()->mainThread.suppressGC) +AutoSuppressGC::AutoSuppressGC(ExclusiveContext *cx) + : suppressGC_(cx->perThreadData->suppressGC) { suppressGC_++; } diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 220d7bc92ce..e38b603d12e 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -1400,7 +1400,7 @@ class AutoSuppressGC int32_t &suppressGC_; public: - AutoSuppressGC(JSContext *cx); + AutoSuppressGC(ExclusiveContext *cx); AutoSuppressGC(JSCompartment *comp); ~AutoSuppressGC() diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 3e2bda689d9..3c99f27170a 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -47,6 +47,7 @@ using namespace js::types; using namespace js::analyze; using mozilla::DebugOnly; +using mozilla::Maybe; using mozilla::PodArrayZero; using mozilla::PodCopy; using mozilla::PodZero; @@ -259,7 +260,7 @@ types::TypeHasProperty(JSContext *cx, TypeObject *obj, jsid id, const Value &val if (cx->compartment()->types.pendingCount) return true; - Type type = GetValueType(cx, value); + Type type = GetValueType(value); AutoEnterAnalysis enter(cx); @@ -268,7 +269,7 @@ types::TypeHasProperty(JSContext *cx, TypeObject *obj, jsid id, const Value &val * haven't yet been accessed during analysis of the inheriting object. * Don't do the property instantiation now. */ - TypeSet *types = obj->maybeGetProperty(id, cx); + TypeSet *types = obj->maybeGetProperty(cx, id); if (!types) return true; @@ -1127,7 +1128,7 @@ GetSingletonPropertyType(JSContext *cx, JSObject *rawObjArg, HandleId id) if (HasDataProperty(cx, obj, id, v.address())) { if (v.isUndefined()) return Type::UnknownType(); - return GetValueType(cx, v); + return GetValueType(v); } obj = obj->getProto(); @@ -1838,23 +1839,27 @@ HeapTypeSet::HasObjectFlags(JSContext *cx, TypeObject *object, TypeObjectFlags f } static inline void -ObjectStateChange(JSContext *cx, TypeObject *object, bool markingUnknown, bool force) +ObjectStateChange(ExclusiveContext *cxArg, TypeObject *object, bool markingUnknown, bool force) { if (object->unknownProperties()) return; /* All constraints listening to state changes are on the empty id. */ - TypeSet *types = object->maybeGetProperty(JSID_EMPTY, cx); + TypeSet *types = object->maybeGetProperty(cxArg, JSID_EMPTY); /* Mark as unknown after getting the types, to avoid assertion. */ if (markingUnknown) object->flags |= OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES; if (types) { - TypeConstraint *constraint = types->constraintList; - while (constraint) { - constraint->newObjectState(cx, object, force); - constraint = constraint->next; + if (JSContext *cx = cxArg->maybeJSContext()) { + TypeConstraint *constraint = types->constraintList; + while (constraint) { + constraint->newObjectState(cx, object, force); + constraint = constraint->next; + } + } else { + JS_ASSERT(!types->constraintList); } } } @@ -2192,7 +2197,7 @@ StackTypeSet::propertyNeedsBarrier(JSContext *cx, jsid id) if (otype->unknownProperties()) return true; - if (types::HeapTypeSet *propTypes = otype->maybeGetProperty(typeId, cx)) { + if (types::HeapTypeSet *propTypes = otype->maybeGetProperty(cx, typeId)) { if (propTypes->needsBarrier(cx)) return true; } @@ -2612,7 +2617,7 @@ TypeCompartment::processPendingRecompiles(FreeOp *fop) } void -TypeCompartment::setPendingNukeTypes(JSContext *cx) +TypeCompartment::setPendingNukeTypes(ExclusiveContext *cx) { TypeZone *zone = &compartment()->zone()->types; if (!zone->pendingNukeTypes) { @@ -3030,9 +3035,9 @@ NumberTypes(Type a, Type b) * arrays and objects whose type can be fixed. */ static inline Type -GetValueTypeForTable(JSContext *cx, const Value &v) +GetValueTypeForTable(const Value &v) { - Type type = GetValueType(cx, v); + Type type = GetValueType(v); JS_ASSERT(!type.isSingleObject()); return type; } @@ -3058,7 +3063,8 @@ struct types::ArrayTableKey }; void -TypeCompartment::setTypeToHomogenousArray(JSContext *cx, JSObject *obj, Type elementType) +TypeCompartment::setTypeToHomogenousArray(ExclusiveContext *cx, + JSObject *obj, Type elementType) { if (!arrayTypeTable) { arrayTypeTable = cx->new_(); @@ -3097,7 +3103,7 @@ TypeCompartment::setTypeToHomogenousArray(JSContext *cx, JSObject *obj, Type ele } void -TypeCompartment::fixArrayType(JSContext *cx, JSObject *obj) +TypeCompartment::fixArrayType(ExclusiveContext *cx, JSObject *obj) { AutoEnterAnalysis enter(cx); @@ -3113,10 +3119,10 @@ TypeCompartment::fixArrayType(JSContext *cx, JSObject *obj) if (len == 0) return; - Type type = GetValueTypeForTable(cx, obj->getDenseElement(0)); + Type type = GetValueTypeForTable(obj->getDenseElement(0)); for (unsigned i = 1; i < len; i++) { - Type ntype = GetValueTypeForTable(cx, obj->getDenseElement(i)); + Type ntype = GetValueTypeForTable(obj->getDenseElement(i)); if (ntype != type) { if (NumberTypes(type, ntype)) type = Type::DoubleType(); @@ -3129,17 +3135,14 @@ TypeCompartment::fixArrayType(JSContext *cx, JSObject *obj) } void -types::FixRestArgumentsType(ExclusiveContext *cxArg, JSObject *obj) +types::FixRestArgumentsType(ExclusiveContext *cx, JSObject *obj) { - if (cxArg->isJSContext()) { - JSContext *cx = cxArg->asJSContext(); - if (cx->typeInferenceEnabled()) - cx->compartment()->types.fixRestArgumentsType(cx, obj); - } + if (cx->typeInferenceEnabled()) + cx->compartment()->types.fixRestArgumentsType(cx, obj); } void -TypeCompartment::fixRestArgumentsType(JSContext *cx, JSObject *obj) +TypeCompartment::fixRestArgumentsType(ExclusiveContext *cx, JSObject *obj) { AutoEnterAnalysis enter(cx); @@ -3199,14 +3202,14 @@ struct types::ObjectTableEntry }; static inline void -UpdateObjectTableEntryTypes(JSContext *cx, ObjectTableEntry &entry, +UpdateObjectTableEntryTypes(ExclusiveContext *cx, ObjectTableEntry &entry, IdValuePair *properties, size_t nproperties) { if (entry.object->unknownProperties()) return; for (size_t i = 0; i < nproperties; i++) { Type type = entry.types[i]; - Type ntype = GetValueTypeForTable(cx, properties[i].value); + Type ntype = GetValueTypeForTable(properties[i].value); if (ntype == type) continue; if (ntype.isPrimitive(JSVAL_TYPE_INT32) && @@ -3226,7 +3229,7 @@ UpdateObjectTableEntryTypes(JSContext *cx, ObjectTableEntry &entry, } void -TypeCompartment::fixObjectType(JSContext *cx, JSObject *obj) +TypeCompartment::fixObjectType(ExclusiveContext *cx, JSObject *obj) { AutoEnterAnalysis enter(cx); @@ -3299,7 +3302,7 @@ TypeCompartment::fixObjectType(JSContext *cx, JSObject *obj) for (size_t i = 0; i < properties.length(); i++) { ids[i] = properties[i].id; - types[i] = GetValueTypeForTable(cx, obj->getSlot(i)); + types[i] = GetValueTypeForTable(obj->getSlot(i)); if (!objType->unknownProperties()) objType->addPropertyType(cx, IdToTypeId(ids[i]), types[i]); } @@ -3427,7 +3430,7 @@ TypeObject::getFromPrototypes(JSContext *cx, jsid id, TypeSet *types, bool force } static inline void -UpdatePropertyType(JSContext *cx, TypeSet *types, JSObject *obj, Shape *shape, +UpdatePropertyType(ExclusiveContext *cx, TypeSet *types, JSObject *obj, Shape *shape, bool force) { types->setOwnProperty(cx, false); @@ -3445,14 +3448,14 @@ UpdatePropertyType(JSContext *cx, TypeSet *types, JSObject *obj, Shape *shape, * not collated into the JSID_VOID property (see propertySet comment). */ if (force || !value.isUndefined()) { - Type type = GetValueType(cx, value); + Type type = GetValueType(value); types->addType(cx, type); } } } bool -TypeObject::addProperty(JSContext *cx, jsid id, Property **pprop) +TypeObject::addProperty(ExclusiveContext *cx, jsid id, Property **pprop) { JS_ASSERT(!*pprop); Property *base = cx->typeLifoAlloc().new_(id); @@ -3483,7 +3486,7 @@ TypeObject::addProperty(JSContext *cx, jsid id, Property **pprop) for (size_t i = 0; i < singleton->getDenseInitializedLength(); i++) { const Value &value = singleton->getDenseElement(i); if (!value.isMagic(JS_ELEMENTS_HOLE)) { - Type type = GetValueType(cx, value); + Type type = GetValueType(value); base->types.setOwnProperty(cx, false); base->types.addType(cx, type); } @@ -3514,7 +3517,7 @@ TypeObject::addProperty(JSContext *cx, jsid id, Property **pprop) } bool -TypeObject::addDefiniteProperties(JSContext *cx, JSObject *obj) +TypeObject::addDefiniteProperties(ExclusiveContext *cx, JSObject *obj) { if (unknownProperties()) return true; @@ -3567,7 +3570,7 @@ TypeObject::matchDefiniteProperties(HandleObject obj) } inline void -InlineAddTypeProperty(JSContext *cx, TypeObject *obj, jsid id, Type type) +InlineAddTypeProperty(ExclusiveContext *cx, TypeObject *obj, jsid id, Type type) { JS_ASSERT(id == IdToTypeId(id)); @@ -3583,19 +3586,19 @@ InlineAddTypeProperty(JSContext *cx, TypeObject *obj, jsid id, Type type) } void -TypeObject::addPropertyType(JSContext *cx, jsid id, Type type) +TypeObject::addPropertyType(ExclusiveContext *cx, jsid id, Type type) { InlineAddTypeProperty(cx, this, id, type); } void -TypeObject::addPropertyType(JSContext *cx, jsid id, const Value &value) +TypeObject::addPropertyType(ExclusiveContext *cx, jsid id, const Value &value) { - InlineAddTypeProperty(cx, this, id, GetValueType(cx, value)); + InlineAddTypeProperty(cx, this, id, GetValueType(value)); } void -TypeObject::addPropertyType(JSContext *cx, const char *name, Type type) +TypeObject::addPropertyType(ExclusiveContext *cx, const char *name, Type type) { jsid id = JSID_VOID; if (name) { @@ -3611,13 +3614,13 @@ TypeObject::addPropertyType(JSContext *cx, const char *name, Type type) } void -TypeObject::addPropertyType(JSContext *cx, const char *name, const Value &value) +TypeObject::addPropertyType(ExclusiveContext *cx, const char *name, const Value &value) { - addPropertyType(cx, name, GetValueType(cx, value)); + addPropertyType(cx, name, GetValueType(value)); } void -TypeObject::markPropertyConfigured(JSContext *cx, jsid id) +TypeObject::markPropertyConfigured(ExclusiveContext *cx, jsid id) { AutoEnterAnalysis enter(cx); @@ -3629,24 +3632,28 @@ TypeObject::markPropertyConfigured(JSContext *cx, jsid id) } void -TypeObject::markStateChange(JSContext *cx) +TypeObject::markStateChange(ExclusiveContext *cxArg) { if (unknownProperties()) return; - AutoEnterAnalysis enter(cx); - TypeSet *types = maybeGetProperty(JSID_EMPTY, cx); + AutoEnterAnalysis enter(cxArg); + TypeSet *types = maybeGetProperty(cxArg, JSID_EMPTY); if (types) { - TypeConstraint *constraint = types->constraintList; - while (constraint) { - constraint->newObjectState(cx, this, true); - constraint = constraint->next; + if (JSContext *cx = cxArg->maybeJSContext()) { + TypeConstraint *constraint = types->constraintList; + while (constraint) { + constraint->newObjectState(cx, this, true); + constraint = constraint->next; + } + } else { + JS_ASSERT(!types->constraintList); } } } void -TypeObject::setFlags(JSContext *cx, TypeObjectFlags flags) +TypeObject::setFlags(ExclusiveContext *cx, TypeObjectFlags flags) { if ((this->flags & flags) == flags) return; @@ -3667,7 +3674,7 @@ TypeObject::setFlags(JSContext *cx, TypeObjectFlags flags) } void -TypeObject::markUnknown(JSContext *cx) +TypeObject::markUnknown(ExclusiveContext *cx) { AutoEnterAnalysis enter(cx); @@ -3701,7 +3708,7 @@ TypeObject::markUnknown(JSContext *cx) } void -TypeObject::clearNewScript(JSContext *cx) +TypeObject::clearNewScript(ExclusiveContext *cx) { JS_ASSERT(!(flags & OBJECT_FLAG_NEW_SCRIPT_CLEARED)); flags |= OBJECT_FLAG_NEW_SCRIPT_CLEARED; @@ -3744,69 +3751,74 @@ TypeObject::clearNewScript(JSContext *cx) * script keeps track of where each property is initialized so we can walk * the stack and fix up any such objects. */ - Vector pcOffsets(cx); - for (ScriptFrameIter iter(cx); !iter.done(); ++iter) { - pcOffsets.append(uint32_t(iter.pc() - iter.script()->code)); - if (iter.isConstructing() && - iter.callee() == newScript->fun && - iter.thisv().isObject() && - !iter.thisv().toObject().hasLazyType() && - iter.thisv().toObject().type() == this) - { - RootedObject obj(cx, &iter.thisv().toObject()); + if (cx->isJSContext()) { + Vector pcOffsets(cx); + for (ScriptFrameIter iter(cx->asJSContext()); !iter.done(); ++iter) { + pcOffsets.append(uint32_t(iter.pc() - iter.script()->code)); + if (iter.isConstructing() && + iter.callee() == newScript->fun && + iter.thisv().isObject() && + !iter.thisv().toObject().hasLazyType() && + iter.thisv().toObject().type() == this) + { + RootedObject obj(cx, &iter.thisv().toObject()); - /* Whether all identified 'new' properties have been initialized. */ - bool finished = false; + /* Whether all identified 'new' properties have been initialized. */ + bool finished = false; - /* If not finished, number of properties that have been added. */ - uint32_t numProperties = 0; + /* If not finished, number of properties that have been added. */ + uint32_t numProperties = 0; - /* - * If non-zero, we are scanning initializers in a call which has - * already finished. - */ - size_t depth = 0; - size_t callDepth = pcOffsets.length() - 1; - uint32_t offset = pcOffsets[callDepth]; + /* + * If non-zero, we are scanning initializers in a call which has + * already finished. + */ + size_t depth = 0; + size_t callDepth = pcOffsets.length() - 1; + uint32_t offset = pcOffsets[callDepth]; - for (TypeNewScript::Initializer *init = newScript->initializerList;; init++) { - if (init->kind == TypeNewScript::Initializer::SETPROP) { - if (!depth && init->offset > offset) { - /* Advanced past all properties which have been initialized. */ - break; - } - numProperties++; - } else if (init->kind == TypeNewScript::Initializer::FRAME_PUSH) { - if (depth) { - depth++; - } else if (init->offset > offset) { - /* Advanced past all properties which have been initialized. */ - break; - } else if (init->offset == offset) { - if (!callDepth) + for (TypeNewScript::Initializer *init = newScript->initializerList;; init++) { + if (init->kind == TypeNewScript::Initializer::SETPROP) { + if (!depth && init->offset > offset) { + /* Advanced past all properties which have been initialized. */ break; - offset = pcOffsets[--callDepth]; + } + numProperties++; + } else if (init->kind == TypeNewScript::Initializer::FRAME_PUSH) { + if (depth) { + depth++; + } else if (init->offset > offset) { + /* Advanced past all properties which have been initialized. */ + break; + } else if (init->offset == offset) { + if (!callDepth) + break; + offset = pcOffsets[--callDepth]; + } else { + /* This call has already finished. */ + depth = 1; + } + } else if (init->kind == TypeNewScript::Initializer::FRAME_POP) { + if (depth) { + depth--; + } else { + /* This call has not finished yet. */ + break; + } } else { - /* This call has already finished. */ - depth = 1; - } - } else if (init->kind == TypeNewScript::Initializer::FRAME_POP) { - if (depth) { - depth--; - } else { - /* This call has not finished yet. */ + JS_ASSERT(init->kind == TypeNewScript::Initializer::DONE); + finished = true; break; } - } else { - JS_ASSERT(init->kind == TypeNewScript::Initializer::DONE); - finished = true; - break; } - } - if (!finished) - obj->rollbackProperties(cx, numProperties); + if (!finished) + obj->rollbackProperties(cx, numProperties); + } } + } else { + // Threads with an ExclusiveContext are not allowed to run scripts. + JS_ASSERT(!cx->perThreadData->activation()); } /* We NULL out newScript *before* freeing it so the write barrier works. */ @@ -5029,7 +5041,7 @@ AnalyzePoppedThis(JSContext *cx, SSAUseChain *use, if (shape && shape->hasSlot()) { Value protov = type->proto->getSlot(shape->slot()); TypeSet *types = TypeScript::BytecodeTypes(script, pc); - types->addType(cx, GetValueType(cx, protov)); + types->addType(cx, GetValueType(protov)); } return true; @@ -5530,7 +5542,7 @@ types::TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const return; } - Type type = GetValueType(cx, rval); + Type type = GetValueType(rval); TypeSet *types = TypeScript::BytecodeTypes(script, pc); if (types->hasType(type)) return; @@ -5804,14 +5816,12 @@ JSScript::makeAnalysis(JSContext *cx) } /* static */ bool -JSFunction::setTypeForScriptedFunction(ExclusiveContext *cxArg, HandleFunction fun, +JSFunction::setTypeForScriptedFunction(ExclusiveContext *cx, HandleFunction fun, bool singleton /* = false */) { - if (!cxArg->typeInferenceEnabled()) + if (!cx->typeInferenceEnabled()) return true; - JSContext *cx = cxArg->asJSContext(); - if (singleton) { if (!setSingletonType(cx, fun)) return false; @@ -6051,7 +6061,7 @@ ExclusiveContext::getNewType(Class *clasp, TaggedProto proto_, JSFunction *fun_) * 'prototype' property of some scripted function. */ if (type->newScript && type->newScript->fun != fun_) - type->clearNewScript(asJSContext()); + type->clearNewScript(this); return type; } @@ -6077,8 +6087,7 @@ ExclusiveContext::getNewType(Class *clasp, TaggedProto proto_, JSFunction *fun_) if (!typeInferenceEnabled()) return type; - JSContext *cx = asJSContext(); - AutoEnterAnalysis enter(cx); + AutoEnterAnalysis enter(this); /* * Set the special equality flag for types whose prototype also has the @@ -6086,22 +6095,22 @@ ExclusiveContext::getNewType(Class *clasp, TaggedProto proto_, JSFunction *fun_) * types and the possible js::Class of objects with that type. */ if (proto.isObject()) { - RootedObject obj(cx, proto.toObject()); + RootedObject obj(this, proto.toObject()); if (fun) - CheckNewScriptProperties(cx, type, fun); + CheckNewScriptProperties(asJSContext(), type, fun); if (obj->is()) { - AddTypeProperty(cx, type, "source", types::Type::StringType()); - AddTypeProperty(cx, type, "global", types::Type::BooleanType()); - AddTypeProperty(cx, type, "ignoreCase", types::Type::BooleanType()); - AddTypeProperty(cx, type, "multiline", types::Type::BooleanType()); - AddTypeProperty(cx, type, "sticky", types::Type::BooleanType()); - AddTypeProperty(cx, type, "lastIndex", types::Type::Int32Type()); + AddTypeProperty(this, type, "source", types::Type::StringType()); + AddTypeProperty(this, type, "global", types::Type::BooleanType()); + AddTypeProperty(this, type, "ignoreCase", types::Type::BooleanType()); + AddTypeProperty(this, type, "multiline", types::Type::BooleanType()); + AddTypeProperty(this, type, "sticky", types::Type::BooleanType()); + AddTypeProperty(this, type, "lastIndex", types::Type::Int32Type()); } if (obj->is()) - AddTypeProperty(cx, type, "length", Type::Int32Type()); + AddTypeProperty(this, type, "length", Type::Int32Type()); } /* diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index dda984dbe77..3cfc66369aa 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -204,7 +204,7 @@ class Type }; /* Get the type of a jsval, or zero for an unknown special value. */ -inline Type GetValueType(JSContext *cx, const Value &val); +inline Type GetValueType(const Value &val); /* * Type inference memory management overview. @@ -489,10 +489,10 @@ class TypeSet * Add a type to this set, calling any constraint handlers if this is a new * possible type. */ - inline void addType(JSContext *cx, Type type); + inline void addType(ExclusiveContext *cx, Type type); /* Mark this type set as representing an own property or configured property. */ - inline void setOwnProperty(JSContext *cx, bool configured); + inline void setOwnProperty(ExclusiveContext *cx, bool configured); /* * Add an object to this set using the specified allocator, without @@ -1040,10 +1040,10 @@ struct TypeObject : gc::Cell * assignment, and the own types of the property will be used instead of * aggregate types. */ - inline HeapTypeSet *getProperty(JSContext *cx, jsid id, bool own); + inline HeapTypeSet *getProperty(ExclusiveContext *cx, jsid id, bool own); /* Get a property only if it already exists. */ - inline HeapTypeSet *maybeGetProperty(jsid id, JSContext *cx); + inline HeapTypeSet *maybeGetProperty(ExclusiveContext *cx, jsid id); inline unsigned getPropertyCount(); inline Property *getProperty(unsigned i); @@ -1056,19 +1056,19 @@ struct TypeObject : gc::Cell /* Helpers */ - bool addProperty(JSContext *cx, jsid id, Property **pprop); - bool addDefiniteProperties(JSContext *cx, JSObject *obj); + bool addProperty(ExclusiveContext *cx, jsid id, Property **pprop); + bool addDefiniteProperties(ExclusiveContext *cx, JSObject *obj); bool matchDefiniteProperties(HandleObject obj); void addPrototype(JSContext *cx, TypeObject *proto); - void addPropertyType(JSContext *cx, jsid id, Type type); - void addPropertyType(JSContext *cx, jsid id, const Value &value); - void addPropertyType(JSContext *cx, const char *name, Type type); - void addPropertyType(JSContext *cx, const char *name, const Value &value); - void markPropertyConfigured(JSContext *cx, jsid id); - void markStateChange(JSContext *cx); - void setFlags(JSContext *cx, TypeObjectFlags flags); - void markUnknown(JSContext *cx); - void clearNewScript(JSContext *cx); + void addPropertyType(ExclusiveContext *cx, jsid id, Type type); + void addPropertyType(ExclusiveContext *cx, jsid id, const Value &value); + void addPropertyType(ExclusiveContext *cx, const char *name, Type type); + void addPropertyType(ExclusiveContext *cx, const char *name, const Value &value); + void markPropertyConfigured(ExclusiveContext *cx, jsid id); + void markStateChange(ExclusiveContext *cx); + void setFlags(ExclusiveContext *cx, TypeObjectFlags flags); + void markUnknown(ExclusiveContext *cx); + void clearNewScript(ExclusiveContext *cx); void getFromPrototypes(JSContext *cx, jsid id, TypeSet *types, bool force = false); void print(); @@ -1368,12 +1368,12 @@ struct TypeCompartment ObjectTypeTable *objectTypeTable; private: - void setTypeToHomogenousArray(JSContext *cx, JSObject *obj, Type type); + void setTypeToHomogenousArray(ExclusiveContext *cx, JSObject *obj, Type type); public: - void fixArrayType(JSContext *cx, JSObject *obj); - void fixObjectType(JSContext *cx, JSObject *obj); - void fixRestArgumentsType(JSContext *cx, JSObject *obj); + void fixArrayType(ExclusiveContext *cx, JSObject *obj); + void fixObjectType(ExclusiveContext *cx, JSObject *obj); + void fixRestArgumentsType(ExclusiveContext *cx, JSObject *obj); JSObject *newTypedObject(JSContext *cx, IdValuePair *properties, size_t nproperties); @@ -1414,7 +1414,7 @@ struct TypeCompartment void processPendingRecompiles(FreeOp *fop); /* Mark all types as needing destruction once inference has 'finished'. */ - void setPendingNukeTypes(JSContext *cx); + void setPendingNukeTypes(ExclusiveContext *cx); /* Mark a script as needing recompilation once inference has finished. */ void addPendingRecompile(JSContext *cx, const RecompileInfo &info); diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index 2028f065e00..f2aebf853f5 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -185,9 +185,8 @@ Type::ObjectType(TypeObjectKey *obj) } inline Type -GetValueType(JSContext *cx, const Value &val) +GetValueType(const Value &val) { - JS_ASSERT(cx->typeInferenceEnabled()); if (val.isDouble()) return Type::DoubleType(); if (val.isObject()) @@ -310,10 +309,10 @@ struct AutoEnterAnalysis JSCompartment *compartment; bool oldActiveAnalysis; - AutoEnterAnalysis(JSContext *cx) + AutoEnterAnalysis(ExclusiveContext *cx) : suppressGC(cx) { - init(cx->runtime()->defaultFreeOp(), cx->compartment()); + init(cx->defaultFreeOp(), cx->compartment()); } AutoEnterAnalysis(FreeOp *fop, JSCompartment *comp) @@ -535,7 +534,7 @@ TrackPropertyTypes(ExclusiveContext *cx, JSObject *obj, jsid id) if (!cx->typeInferenceEnabled() || obj->hasLazyType() || obj->type()->unknownProperties()) return false; - if (obj->hasSingletonType() && !obj->type()->maybeGetProperty(id, cx->asJSContext())) + if (obj->hasSingletonType() && !obj->type()->maybeGetProperty(cx, id)) return false; return true; @@ -566,7 +565,7 @@ AddTypePropertyId(ExclusiveContext *cx, JSObject *obj, jsid id, Type type) if (cx->typeInferenceEnabled()) { id = IdToTypeId(id); if (TrackPropertyTypes(cx, obj, id)) - obj->type()->addPropertyType(cx->asJSContext(), id, type); + obj->type()->addPropertyType(cx, id, type); } } @@ -576,19 +575,19 @@ AddTypePropertyId(ExclusiveContext *cx, JSObject *obj, jsid id, const Value &val if (cx->typeInferenceEnabled()) { id = IdToTypeId(id); if (TrackPropertyTypes(cx, obj, id)) - obj->type()->addPropertyType(cx->asJSContext(), id, value); + obj->type()->addPropertyType(cx, id, value); } } inline void -AddTypeProperty(JSContext *cx, TypeObject *obj, const char *name, Type type) +AddTypeProperty(ExclusiveContext *cx, TypeObject *obj, const char *name, Type type) { if (cx->typeInferenceEnabled() && !obj->unknownProperties()) obj->addPropertyType(cx, name, type); } inline void -AddTypeProperty(JSContext *cx, TypeObject *obj, const char *name, const Value &value) +AddTypeProperty(ExclusiveContext *cx, TypeObject *obj, const char *name, const Value &value) { if (cx->typeInferenceEnabled() && !obj->unknownProperties()) obj->addPropertyType(cx, name, value); @@ -599,7 +598,7 @@ inline void MarkTypeObjectFlags(ExclusiveContext *cx, JSObject *obj, TypeObjectFlags flags) { if (cx->typeInferenceEnabled() && !obj->hasLazyType() && !obj->type()->hasAllFlags(flags)) - obj->type()->setFlags(cx->asJSContext(), flags); + obj->type()->setFlags(cx, flags); } /* @@ -630,7 +629,7 @@ MarkTypePropertyConfigured(ExclusiveContext *cx, HandleObject obj, jsid id) if (cx->typeInferenceEnabled()) { id = IdToTypeId(id); if (TrackPropertyTypes(cx, obj, id)) - obj->type()->markPropertyConfigured(cx->asJSContext(), id); + obj->type()->markPropertyConfigured(cx, id); } } @@ -639,7 +638,7 @@ inline void MarkObjectStateChange(ExclusiveContext *cx, JSObject *obj) { if (cx->typeInferenceEnabled() && !obj->hasLazyType() && !obj->type()->unknownProperties()) - obj->type()->markStateChange(cx->asJSContext()); + obj->type()->markStateChange(cx); } /* @@ -648,23 +647,17 @@ MarkObjectStateChange(ExclusiveContext *cx, JSObject *obj) */ inline void -FixArrayType(ExclusiveContext *cxArg, HandleObject obj) +FixArrayType(ExclusiveContext *cx, HandleObject obj) { - if (cxArg->isJSContext()) { - JSContext *cx = cxArg->asJSContext(); - if (cx->typeInferenceEnabled()) - cx->compartment()->types.fixArrayType(cx, obj); - } + if (cx->typeInferenceEnabled()) + cx->compartment()->types.fixArrayType(cx, obj); } inline void -FixObjectType(ExclusiveContext *cxArg, HandleObject obj) +FixObjectType(ExclusiveContext *cx, HandleObject obj) { - if (cxArg->isJSContext()) { - JSContext *cx = cxArg->asJSContext(); - if (cx->typeInferenceEnabled()) - cx->compartment()->types.fixObjectType(cx, obj); - } + if (cx->typeInferenceEnabled()) + cx->compartment()->types.fixObjectType(cx, obj); } /* Interface helpers for JSScript*. */ @@ -970,7 +963,7 @@ TypeScript::SetThis(JSContext *cx, JSScript *script, Type type) TypeScript::SetThis(JSContext *cx, JSScript *script, const js::Value &value) { if (cx->typeInferenceEnabled()) - SetThis(cx, script, GetValueType(cx, value)); + SetThis(cx, script, GetValueType(value)); } /* static */ inline void @@ -992,7 +985,7 @@ TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value) { if (cx->typeInferenceEnabled()) { - Type type = GetValueType(cx, value); + Type type = GetValueType(value); SetArgument(cx, script, arg, type); } } @@ -1280,9 +1273,9 @@ TypeSet::clearObjects() } inline void -TypeSet::addType(JSContext *cx, Type type) +TypeSet::addType(ExclusiveContext *cxArg, Type type) { - JS_ASSERT(cx->compartment()->activeAnalysis); + JS_ASSERT(cxArg->compartment()->activeAnalysis); if (unknown()) return; @@ -1308,14 +1301,14 @@ TypeSet::addType(JSContext *cx, Type type) goto unknownObject; LifoAlloc &alloc = - purged() ? cx->compartment()->analysisLifoAlloc : cx->typeLifoAlloc(); + purged() ? cxArg->compartment()->analysisLifoAlloc : cxArg->typeLifoAlloc(); uint32_t objectCount = baseObjectCount(); TypeObjectKey *object = type.objectKey(); TypeObjectKey **pentry = HashSetInsert (alloc, objectSet, objectCount, object); if (!pentry) { - cx->compartment()->types.setPendingNukeTypes(cx); + cxArg->compartment()->types.setPendingNukeTypes(cxArg); return; } if (*pentry) @@ -1347,17 +1340,20 @@ TypeSet::addType(JSContext *cx, Type type) TypeString(type)); /* Propagate the type to all constraints. */ - TypeConstraint *constraint = constraintList; - while (constraint) { - cx->compartment()->types.addPending(cx, constraint, this, type); - constraint = constraint->next; + if (JSContext *cx = cxArg->maybeJSContext()) { + TypeConstraint *constraint = constraintList; + while (constraint) { + cx->compartment()->types.addPending(cx, constraint, this, type); + constraint = constraint->next; + } + cx->compartment()->types.resolvePending(cx); + } else { + JS_ASSERT(!constraintList); } - - cx->compartment()->types.resolvePending(cx); } inline void -TypeSet::setOwnProperty(JSContext *cx, bool configured) +TypeSet::setOwnProperty(ExclusiveContext *cxArg, bool configured) { TypeFlags nflags = TYPE_FLAG_OWN_PROPERTY | (configured ? TYPE_FLAG_CONFIGURED_PROPERTY : 0); @@ -1367,10 +1363,14 @@ TypeSet::setOwnProperty(JSContext *cx, bool configured) flags |= nflags; /* Propagate the change to all constraints. */ - TypeConstraint *constraint = constraintList; - while (constraint) { - constraint->newPropertyState(cx, this); - constraint = constraint->next; + if (JSContext *cx = cxArg->maybeJSContext()) { + TypeConstraint *constraint = constraintList; + while (constraint) { + constraint->newPropertyState(cx, this); + constraint = constraint->next; + } + } else { + JS_ASSERT(!constraintList); } } @@ -1476,7 +1476,7 @@ TypeObject::setBasePropertyCount(uint32_t count) } inline HeapTypeSet * -TypeObject::getProperty(JSContext *cx, jsid id, bool own) +TypeObject::getProperty(ExclusiveContext *cx, jsid id, bool own) { JS_ASSERT(cx->compartment()->activeAnalysis); @@ -1524,7 +1524,7 @@ TypeObject::getProperty(JSContext *cx, jsid id, bool own) } inline HeapTypeSet * -TypeObject::maybeGetProperty(jsid id, JSContext *cx) +TypeObject::maybeGetProperty(ExclusiveContext *cx, jsid id) { JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id)); JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id)); diff --git a/js/src/jsobj.h b/js/src/jsobj.h index cf13160a806..2247915a47e 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -377,7 +377,7 @@ class JSObject : public js::ObjectImpl inline void prepareSlotRangeForOverwrite(size_t start, size_t end); inline void prepareElementRangeForOverwrite(size_t start, size_t end); - void rollbackProperties(JSContext *cx, uint32_t slotSpan); + void rollbackProperties(js::ExclusiveContext *cx, uint32_t slotSpan); inline void nativeSetSlot(uint32_t slot, const js::Value &value); static inline void nativeSetSlotWithType(js::ExclusiveContext *cx, diff --git a/js/src/jsworkers.cpp b/js/src/jsworkers.cpp index 3a10377accd..8179f3a2f35 100644 --- a/js/src/jsworkers.cpp +++ b/js/src/jsworkers.cpp @@ -226,12 +226,7 @@ js::StartOffThreadParseScript(JSContext *cx, const CompileOptions &options, if (!global) return false; - // For now, type inference is always disabled in exclusive zones, as type - // inference data is not merged between zones when finishing the off thread - // parse. This restriction would be fairly easy to lift. - JS_ASSERT(!cx->typeInferenceEnabled()); - global->zone()->types.inferenceEnabled = false; - + global->zone()->types.inferenceEnabled = cx->typeInferenceEnabled(); JS_SetCompartmentPrincipals(global->compartment(), cx->compartment()->principals); RootedObject obj(cx); diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index a374cadc48f..81e32a02540 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -407,7 +407,9 @@ JSRuntime::~JSRuntime() PR_DestroyLock(exclusiveAccessLock); JS_ASSERT(!numExclusiveThreads); - exclusiveThreadsPaused = true; // Avoid bogus asserts during teardown. + + // Avoid bogus asserts during teardown. + exclusiveThreadsPaused = true; #endif /* diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index b10aeccffbe..4ea9e3e232b 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -938,7 +938,7 @@ JSObject::clear(JSContext *cx, HandleObject obj) } void -JSObject::rollbackProperties(JSContext *cx, uint32_t slotSpan) +JSObject::rollbackProperties(ExclusiveContext *cx, uint32_t slotSpan) { /* * Remove properties from this object until it has a matching slot span.