From ea1ffaab452dd9c4361727adcee2bc0f70fff68b Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Thu, 29 Nov 2012 10:22:10 -0800 Subject: [PATCH] Bug 816776 - Add debug-mode exact rooting assertions for Shape; r=sfink --HG-- extra : rebase_source : fbd47f598964cbb03dcc782198c10164e09a26f2 --- js/src/frontend/Parser.cpp | 2 +- js/src/frontend/SharedContext-inl.h | 2 +- js/src/gc/Marking.cpp | 24 +-- js/src/gc/Marking.h | 2 +- js/src/gc/Root.h | 22 ++- js/src/ion/CompilerRoot.h | 5 +- js/src/ion/IonBuilder.cpp | 23 ++- js/src/ion/IonBuilder.h | 6 +- js/src/ion/IonCaches.cpp | 39 ++-- js/src/ion/IonCaches.h | 10 +- js/src/ion/MIR.h | 12 +- js/src/ion/VMFunctions.cpp | 2 +- js/src/ion/shared/Assembler-shared.h | 6 + js/src/jsapi.cpp | 33 ++-- js/src/jsarray.cpp | 46 ++--- js/src/jsarray.h | 2 +- js/src/jsatom.cpp | 1 + js/src/jscntxt.cpp | 2 +- js/src/jscntxt.h | 2 +- js/src/jsdbgapi.cpp | 4 +- js/src/jsfriendapi.cpp | 4 +- js/src/jsgcinlines.h | 2 +- js/src/jsinfer.cpp | 45 +++-- js/src/jsinferinlines.h | 11 +- js/src/jsinterpinlines.h | 11 +- js/src/jsiter.cpp | 11 +- js/src/jsmemorymetrics.cpp | 2 +- js/src/jsobj.cpp | 187 +++++++++---------- js/src/jsobj.h | 80 ++++---- js/src/jsobjinlines.h | 16 +- js/src/jspropertycacheinlines.h | 6 +- js/src/jspropertytree.cpp | 122 ++++++------- js/src/jspropertytree.h | 30 +-- js/src/jsprvtd.h | 10 - js/src/jsscope.cpp | 262 +++++++++++++-------------- js/src/jsscope.h | 115 ++++++------ js/src/jsscopeinlines.h | 18 +- js/src/jsscript.cpp | 6 +- js/src/jsscript.h | 4 +- js/src/jsstr.cpp | 6 +- js/src/jswatchpoint.cpp | 2 +- js/src/jsxml.cpp | 16 +- js/src/methodjit/BaseAssembler.h | 5 +- js/src/methodjit/Compiler.cpp | 14 +- js/src/methodjit/FastOps.cpp | 4 +- js/src/methodjit/MethodJIT.cpp | 4 +- js/src/methodjit/MethodJIT.h | 2 +- js/src/methodjit/MonoIC.cpp | 67 +++---- js/src/methodjit/MonoIC.h | 2 +- js/src/methodjit/PolyIC.cpp | 33 ++-- js/src/methodjit/PolyIC.h | 6 +- js/src/methodjit/StubCalls-inl.h | 19 +- js/src/shell/js.cpp | 4 +- js/src/vm/Debugger.cpp | 8 +- js/src/vm/ObjectImpl-inl.h | 8 +- js/src/vm/ObjectImpl.cpp | 20 +- js/src/vm/ObjectImpl.h | 17 +- js/src/vm/RegExpObject.cpp | 38 ++-- js/src/vm/RegExpObject.h | 2 +- js/src/vm/ScopeObject.cpp | 39 ++-- js/src/vm/ScopeObject.h | 6 +- js/src/vm/String.h | 5 + js/src/vm/StringObject-inl.h | 6 +- js/src/vm/StringObject.h | 2 +- 64 files changed, 797 insertions(+), 725 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 7ef18913cda..c1db6ef8ab2 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -2075,7 +2075,7 @@ BindLet(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser) */ bool redeclared; RootedId id(cx, NameToId(name)); - Shape *shape = StaticBlockObject::addVar(cx, blockObj, id, blockCount, &redeclared); + RootedShape shape(cx, StaticBlockObject::addVar(cx, blockObj, id, blockCount, &redeclared)); if (!shape) { if (redeclared) ReportRedeclaration(cx, parser, pn, false, name); diff --git a/js/src/frontend/SharedContext-inl.h b/js/src/frontend/SharedContext-inl.h index 03ed9f498c3..0ecfee4c1d3 100644 --- a/js/src/frontend/SharedContext-inl.h +++ b/js/src/frontend/SharedContext-inl.h @@ -123,7 +123,7 @@ frontend::LexicalLookup(ContextT *ct, HandleAtom atom, int *slotp, typename Cont continue; StaticBlockObject &blockObj = *stmt->blockObj; - Shape *shape = blockObj.nativeLookup(ct->sc->context, AtomToId(atom)); + UnrootedShape shape = blockObj.nativeLookup(ct->sc->context, AtomToId(atom)); if (shape) { JS_ASSERT(shape->hasShortID()); diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index d61c726fccf..e5080dbb0f0 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -71,7 +71,7 @@ static inline void PushMarkStack(GCMarker *gcmarker, JSScript *thing); static inline void -PushMarkStack(GCMarker *gcmarker, Shape *thing); +PushMarkStack(GCMarker *gcmarker, UnrootedShape thing); static inline void PushMarkStack(GCMarker *gcmarker, JSString *thing); @@ -84,7 +84,7 @@ namespace gc { static void MarkChildren(JSTracer *trc, JSString *str); static void MarkChildren(JSTracer *trc, JSScript *script); -static void MarkChildren(JSTracer *trc, Shape *shape); +static void MarkChildren(JSTracer *trc, UnrootedShape shape); static void MarkChildren(JSTracer *trc, UnrootedBaseShape base); static void MarkChildren(JSTracer *trc, types::TypeObject *type); static void MarkChildren(JSTracer *trc, ion::IonCode *code); @@ -292,12 +292,14 @@ Is##base##Marked(EncapsulatedPtr *thingp) return IsMarked(thingp->unsafeGet()); \ } \ \ -bool Is##base##AboutToBeFinalized(type **thingp) \ +bool \ +Is##base##AboutToBeFinalized(type **thingp) \ { \ return IsAboutToBeFinalized(thingp); \ } \ \ -bool Is##base##AboutToBeFinalized(EncapsulatedPtr *thingp) \ +bool \ +Is##base##AboutToBeFinalized(EncapsulatedPtr *thingp) \ { \ return IsAboutToBeFinalized(thingp->unsafeGet()); \ } @@ -731,10 +733,10 @@ PushMarkStack(GCMarker *gcmarker, JSScript *thing) } static void -ScanShape(GCMarker *gcmarker, Shape *shape); +ScanShape(GCMarker *gcmarker, UnrootedShape shape); static void -PushMarkStack(GCMarker *gcmarker, Shape *thing) +PushMarkStack(GCMarker *gcmarker, UnrootedShape thing) { JS_COMPARTMENT_ASSERT(gcmarker->runtime, thing); @@ -766,7 +768,7 @@ PushMarkStack(GCMarker *gcmarker, UnrootedBaseShape thing) } static void -ScanShape(GCMarker *gcmarker, Shape *shape) +ScanShape(GCMarker *gcmarker, UnrootedShape shape) { restart: PushMarkStack(gcmarker, shape->base()); @@ -930,7 +932,7 @@ gc::MarkChildren(JSTracer *trc, JSScript *script) } static void -gc::MarkChildren(JSTracer *trc, Shape *shape) +gc::MarkChildren(JSTracer *trc, UnrootedShape shape) { shape->markChildren(trc); } @@ -990,7 +992,7 @@ MarkCycleCollectorChildren(JSTracer *trc, UnrootedBaseShape base, JSObject **pre * parent pointer will only be marked once. */ void -gc::MarkCycleCollectorChildren(JSTracer *trc, Shape *shape) +gc::MarkCycleCollectorChildren(JSTracer *trc, UnrootedShape shape) { JSObject *prevParent = NULL; do { @@ -1021,7 +1023,7 @@ ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type) if (type->newScript) { PushMarkStack(gcmarker, type->newScript->fun); - PushMarkStack(gcmarker, type->newScript->shape); + PushMarkStack(gcmarker, type->newScript->shape.get()); } if (type->interpretedFunction) @@ -1356,7 +1358,7 @@ GCMarker::processMarkStackTop(SliceBudget &budget) types::TypeObject *type = obj->typeFromGC(); PushMarkStack(this, type); - Shape *shape = obj->lastProperty(); + UnrootedShape shape = obj->lastProperty(); PushMarkStack(this, shape); /* Call the trace hook if necessary. */ diff --git a/js/src/gc/Marking.h b/js/src/gc/Marking.h index e6a2b50379d..e4d88bd458a 100644 --- a/js/src/gc/Marking.h +++ b/js/src/gc/Marking.h @@ -236,7 +236,7 @@ MarkChildren(JSTracer *trc, JSObject *obj); * JS_TraceShapeCycleCollectorChildren. */ void -MarkCycleCollectorChildren(JSTracer *trc, Shape *shape); +MarkCycleCollectorChildren(JSTracer *trc, UnrootedShape shape); void PushArena(GCMarker *gcmarker, ArenaHeader *aheader); diff --git a/js/src/gc/Root.h b/js/src/gc/Root.h index 0f56988d44c..4c792550651 100644 --- a/js/src/gc/Root.h +++ b/js/src/gc/Root.h @@ -279,15 +279,17 @@ class MutableHandle : public js::MutableHandleBase } template - inline - MutableHandle(js::Rooted *root, - typename mozilla::EnableIf::value, int>::Type dummy = 0); + inline MutableHandle(js::Rooted *root, + typename mozilla::EnableIf::value, int>::Type dummy = 0); void set(T v) { JS_ASSERT(!js::RootMethods::poisoned(v)); *ptr = v; } + template + inline void set(const js::Unrooted &v); + /* * This may be called only if the location of the T is guaranteed * to be marked (for some reason other than being a Rooted), @@ -478,6 +480,13 @@ class Unrooted ptr_ = other; return *this; } + Unrooted &operator=(Unrooted other) { + JS_ASSERT(other.ptr_ != UninitializedTag()); + if (ptr_ == UninitializedTag()) + EnterAssertNoGCScope(); + ptr_ = other.ptr_; + return *this; + } operator T() const { return (ptr_ == UninitializedTag()) ? NULL : ptr_; } T *operator&() { return &ptr_; } @@ -859,6 +868,13 @@ MutableHandle::MutableHandle(js::Rooted *root, ptr = root->address(); } +template template +inline void MutableHandle::set(const js::Unrooted &v) +{ + JS_ASSERT(!js::RootMethods::poisoned(v)); + *ptr = static_cast(v); +} + /* * The scoped guard object AutoAssertNoGC forces the GC to assert if a GC is * attempted while the guard object is live. If you have a GC-unsafe operation diff --git a/js/src/ion/CompilerRoot.h b/js/src/ion/CompilerRoot.h index 6a5382d5db4..150df297b9f 100644 --- a/js/src/ion/CompilerRoot.h +++ b/js/src/ion/CompilerRoot.h @@ -41,6 +41,7 @@ class CompilerRoot : public CompilerRootNode public: operator T () const { return static_cast(ptr); } + operator Unrooted () const { return static_cast(ptr); } T operator ->() const { return static_cast(ptr); } private: @@ -49,9 +50,11 @@ class CompilerRoot : public CompilerRootNode CompilerRoot &operator =(const CompilerRoot &) MOZ_DELETE; }; -typedef CompilerRoot CompilerRootObject; +typedef CompilerRoot CompilerRootObject; typedef CompilerRoot CompilerRootFunction; +typedef CompilerRoot CompilerRootScript; typedef CompilerRoot CompilerRootPropertyName; +typedef CompilerRoot CompilerRootShape; typedef CompilerRoot CompilerRootValue; } // namespace ion diff --git a/js/src/ion/IonBuilder.cpp b/js/src/ion/IonBuilder.cpp index e73887f0264..d274e3a1c92 100644 --- a/js/src/ion/IonBuilder.cpp +++ b/js/src/ion/IonBuilder.cpp @@ -4854,6 +4854,8 @@ bool IonBuilder::pushTypeBarrier(MInstruction *ins, types::StackTypeSet *actual, types::StackTypeSet *observed) { + AutoAssertNoGC nogc; + // If the instruction has no side effects, we'll resume the entire operation. // The actual type barrier will occur in the interpreter. If the // instruction is effectful, even if it has a singleton type, there @@ -4971,7 +4973,7 @@ IonBuilder::jsop_getgname(HandlePropertyName name) // For the fastest path, the property must be found, and it must be found // as a normal data property on exactly the global object. - const js::Shape *shape = globalObj->nativeLookup(cx, id); + RootedShape shape(cx, globalObj->nativeLookup(cx, id)); if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot()) return jsop_getname(name); @@ -5048,7 +5050,7 @@ IonBuilder::jsop_setgname(HandlePropertyName name) // For the fastest path, the property must be found, and it must be found // as a normal data property on exactly the global object. - const js::Shape *shape = globalObj->nativeLookup(cx, id); + RootedShape shape(cx, globalObj->nativeLookup(cx, id)); if (!shape || !shape->hasDefaultSetter() || !shape->writable() || !shape->hasSlot()) return jsop_setprop(name); @@ -6145,7 +6147,7 @@ IonBuilder::invalidatedIdempotentCache() } bool -IonBuilder::loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType) +IonBuilder::loadSlot(MDefinition *obj, HandleShape shape, MIRType rvalType) { JS_ASSERT(shape->hasDefaultGetter()); JS_ASSERT(shape->hasSlot()); @@ -6175,7 +6177,7 @@ IonBuilder::loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType) } bool -IonBuilder::storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier) +IonBuilder::storeSlot(MDefinition *obj, UnrootedShape shape, MDefinition *value, bool needsBarrier) { JS_ASSERT(shape->hasDefaultSetter()); JS_ASSERT(shape->writable()); @@ -6400,13 +6402,14 @@ bool IonBuilder::getPropTryMonomorphic(bool *emitted, HandleId id, types::StackTypeSet *barrier, TypeOracle::Unary unary, TypeOracle::UnaryTypes unaryTypes) { + AssertCanGC(); JS_ASSERT(*emitted == false); bool accessGetter = oracle->propertyReadAccessGetter(script(), pc); if (unary.ival != MIRType_Object) return true; - Shape *objShape = mjit::GetPICSingleShape(cx, script(), pc, info().constructing()); + RootedShape objShape(cx, mjit::GetPICSingleShape(cx, script(), pc, info().constructing())); if (!objShape || objShape->inDictionary()) { spew("GETPROP not monomorphic"); return true; @@ -6421,7 +6424,7 @@ IonBuilder::getPropTryMonomorphic(bool *emitted, HandleId id, types::StackTypeSe obj = addShapeGuard(obj, objShape, Bailout_CachedShapeGuard); spew("Inlining monomorphic GETPROP"); - Shape *shape = objShape->search(cx, id); + RootedShape shape(cx, objShape->search(cx, id)); JS_ASSERT(shape); MIRType rvalType = unary.rval; @@ -6561,7 +6564,7 @@ IonBuilder::jsop_setprop(HandlePropertyName name) if (monitored) { ins = MCallSetProperty::New(obj, value, name, script()->strict); } else { - Shape *objShape; + UnrootedShape objShape; if ((objShape = mjit::GetPICSingleShape(cx, script(), pc, info().constructing())) && !objShape->inDictionary()) { @@ -6571,7 +6574,7 @@ IonBuilder::jsop_setprop(HandlePropertyName name) // on dictionary mode shapes that aren't lastProperty is invalid. obj = addShapeGuard(obj, objShape, Bailout_CachedShapeGuard); - Shape *shape = objShape->search(cx, NameToId(name)); + UnrootedShape shape = DropUnrooted(objShape)->search(cx, NameToId(name)); JS_ASSERT(shape); spew("Inlining monomorphic SETPROP"); @@ -6579,7 +6582,7 @@ IonBuilder::jsop_setprop(HandlePropertyName name) jsid typeId = types::MakeTypeId(cx, id); bool needsBarrier = oracle->propertyWriteNeedsBarrier(script(), pc, typeId); - return storeSlot(obj, shape, value, needsBarrier); + return storeSlot(obj, DropUnrooted(shape), value, needsBarrier); } spew("SETPROP not monomorphic"); @@ -6962,7 +6965,7 @@ IonBuilder::addBoundsCheck(MDefinition *index, MDefinition *length) } MInstruction * -IonBuilder::addShapeGuard(MDefinition *obj, const Shape *shape, BailoutKind bailoutKind) +IonBuilder::addShapeGuard(MDefinition *obj, const UnrootedShape shape, BailoutKind bailoutKind) { MGuardShape *guard = MGuardShape::New(obj, shape, bailoutKind); current->add(guard); diff --git a/js/src/ion/IonBuilder.h b/js/src/ion/IonBuilder.h index ec4f1aa7e39..4b7685ed91e 100644 --- a/js/src/ion/IonBuilder.h +++ b/js/src/ion/IonBuilder.h @@ -304,14 +304,14 @@ class IonBuilder : public MIRGenerator MDefinition *walkScopeChain(unsigned hops); MInstruction *addBoundsCheck(MDefinition *index, MDefinition *length); - MInstruction *addShapeGuard(MDefinition *obj, const Shape *shape, BailoutKind bailoutKind); + MInstruction *addShapeGuard(MDefinition *obj, const UnrootedShape shape, BailoutKind bailoutKind); JSObject *getNewArrayTemplateObject(uint32_t count); bool invalidatedIdempotentCache(); - bool loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType); - bool storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier); + bool loadSlot(MDefinition *obj, HandleShape shape, MIRType rvalType); + bool storeSlot(MDefinition *obj, UnrootedShape shape, MDefinition *value, bool needsBarrier); // jsop_getprop() helpers. bool getPropTryArgumentsLength(bool *emitted); diff --git a/js/src/ion/IonCaches.cpp b/js/src/ion/IonCaches.cpp index cbec8e6fc60..c45eeb79478 100644 --- a/js/src/ion/IonCaches.cpp +++ b/js/src/ion/IonCaches.cpp @@ -149,7 +149,7 @@ IsCacheableProtoChain(JSObject *obj, JSObject *holder) } static bool -IsCacheableGetPropReadSlot(JSObject *obj, JSObject *holder, const Shape *shape) +IsCacheableGetPropReadSlot(JSObject *obj, JSObject *holder, UnrootedShape shape) { if (!shape || !IsCacheableProtoChain(obj, holder)) return false; @@ -161,7 +161,7 @@ IsCacheableGetPropReadSlot(JSObject *obj, JSObject *holder, const Shape *shape) } static bool -IsCacheableNoProperty(JSObject *obj, JSObject *holder, const Shape *shape, jsbytecode *pc, +IsCacheableNoProperty(JSObject *obj, JSObject *holder, UnrootedShape shape, jsbytecode *pc, const TypedOrValueRegister &output) { if (shape) @@ -212,7 +212,7 @@ IsCacheableNoProperty(JSObject *obj, JSObject *holder, const Shape *shape, jsbyt } static bool -IsCacheableGetPropCallNative(JSObject *obj, JSObject *holder, const Shape *shape) +IsCacheableGetPropCallNative(JSObject *obj, JSObject *holder, UnrootedShape shape) { if (!shape || !IsCacheableProtoChain(obj, holder)) return false; @@ -225,7 +225,7 @@ IsCacheableGetPropCallNative(JSObject *obj, JSObject *holder, const Shape *shape } static bool -IsCacheableGetPropCallPropertyOp(JSObject *obj, JSObject *holder, const Shape *shape) +IsCacheableGetPropCallPropertyOp(JSObject *obj, JSObject *holder, UnrootedShape shape) { if (!shape || !IsCacheableProtoChain(obj, holder)) return false; @@ -243,7 +243,7 @@ struct GetNativePropertyStub CodeOffsetLabel stubCodePatchOffset; void generateReadSlot(JSContext *cx, MacroAssembler &masm, JSObject *obj, PropertyName *propName, - JSObject *holder, const Shape *shape, Register object, TypedOrValueRegister output, + JSObject *holder, HandleShape shape, Register object, TypedOrValueRegister output, RepatchLabel *failures, Label *nonRepatchFailures = NULL) { // If there's a single jump to |failures|, we can patch the shape guard @@ -354,7 +354,7 @@ struct GetNativePropertyStub } bool generateCallGetter(JSContext *cx, MacroAssembler &masm, JSObject *obj, - PropertyName *propName, JSObject *holder, const Shape *shape, + PropertyName *propName, JSObject *holder, HandleShape shape, RegisterSet &liveRegs, Register object, TypedOrValueRegister output, void *returnAddr, jsbytecode *pc, RepatchLabel *failures, Label *nonRepatchFailures = NULL) @@ -619,7 +619,7 @@ struct GetNativePropertyStub bool IonCacheGetProperty::attachReadSlot(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder, - const Shape *shape) + HandleShape shape) { MacroAssembler masm; RepatchLabel failures; @@ -654,9 +654,10 @@ IonCacheGetProperty::attachReadSlot(JSContext *cx, IonScript *ion, JSObject *obj bool IonCacheGetProperty::attachCallGetter(JSContext *cx, IonScript *ion, JSObject *obj, - JSObject *holder, const Shape *shape, + JSObject *holder, HandleShape shape, const SafepointIndex *safepointIndex, void *returnAddr) { + AssertCanGC(); MacroAssembler masm; RepatchLabel failures; @@ -1136,8 +1137,8 @@ IonCacheSetProperty::attachSetterCall(JSContext *cx, IonScript *ion, bool IonCacheSetProperty::attachNativeAdding(JSContext *cx, IonScript *ion, JSObject *obj, - const Shape *oldShape, const Shape *newShape, - const Shape *propShape) + HandleShape oldShape, HandleShape newShape, + HandleShape propShape) { MacroAssembler masm; @@ -1156,7 +1157,7 @@ IonCacheSetProperty::attachNativeAdding(JSContext *cx, IonScript *ion, JSObject JSObject *proto = obj->getProto(); Register protoReg = object(); while (proto) { - Shape *protoShape = proto->lastProperty(); + UnrootedShape protoShape = proto->lastProperty(); // load next prototype masm.loadPtr(Address(protoReg, JSObject::offsetOfType()), protoReg); @@ -1248,7 +1249,7 @@ IsPropertyInlineable(JSObject *obj, IonCacheSetProperty &cache) static bool IsPropertySetInlineable(JSContext *cx, HandleObject obj, HandleId id, MutableHandleShape pshape) { - Shape *shape = obj->nativeLookup(cx, id); + UnrootedShape shape = obj->nativeLookup(cx, id); if (!shape) return false; @@ -1299,7 +1300,7 @@ IsPropertyAddInlineable(JSContext *cx, HandleObject obj, jsid id, uint32_t oldSl if (pShape.get()) return false; - Shape *shape = obj->nativeLookup(cx, id); + RootedShape shape(cx, obj->nativeLookup(cx, id)); if (!shape || shape->inDictionary() || !shape->hasSlot() || !shape->hasDefaultSetter()) return false; @@ -1319,7 +1320,7 @@ IsPropertyAddInlineable(JSContext *cx, HandleObject obj, jsid id, uint32_t oldSl return false; // if prototype defines this property in a non-plain way, don't optimize - const Shape *protoShape = proto->nativeLookup(cx, id); + UnrootedShape protoShape = proto->nativeLookup(cx, id); if (protoShape && !protoShape->hasDefaultSetter()) return false; @@ -1376,7 +1377,7 @@ js::ion::SetPropertyCache(JSContext *cx, size_t cacheIndex, HandleObject obj, Ha } uint32_t oldSlots = obj->numDynamicSlots(); - const Shape *oldShape = obj->lastProperty(); + RootedShape oldShape(cx, obj->lastProperty()); // Set/Add the property on the object, the inlined cache are setup for the next execution. if (!SetProperty(cx, obj, name, value, cache.strict(), isSetName)) @@ -1385,7 +1386,7 @@ js::ion::SetPropertyCache(JSContext *cx, size_t cacheIndex, HandleObject obj, Ha // The property did not exists before, now we can try again to inline the // procedure which is adding the property. if (inlinable && IsPropertyAddInlineable(cx, obj, id, oldSlots, &shape)) { - const Shape *newShape = obj->lastProperty(); + RootedShape newShape(cx, obj->lastProperty()); cache.incrementStubCount(); if (!cache.attachNativeAdding(cx, ion, obj, oldShape, newShape, shape)) return false; @@ -1619,7 +1620,7 @@ IonCacheBindName::attachGlobal(JSContext *cx, IonScript *ion, JSObject *scopeCha static inline void GenerateScopeChainGuard(MacroAssembler &masm, JSObject *scopeObj, - Register scopeObjReg, Shape *shape, Label *failures) + Register scopeObjReg, UnrootedShape shape, Label *failures) { AutoAssertNoGC nogc; if (scopeObj->isCall()) { @@ -1789,8 +1790,10 @@ js::ion::BindNameCache(JSContext *cx, size_t cacheIndex, HandleObject scopeChain } bool -IonCacheName::attach(JSContext *cx, IonScript *ion, HandleObject scopeChain, HandleObject holder, Shape *shape) +IonCacheName::attach(JSContext *cx, IonScript *ion, HandleObject scopeChain, HandleObject holder, + HandleShape shape) { + AssertCanGC(); MacroAssembler masm; Label failures; diff --git a/js/src/ion/IonCaches.h b/js/src/ion/IonCaches.h index d582fc2090f..60e450b433f 100644 --- a/js/src/ion/IonCaches.h +++ b/js/src/ion/IonCaches.h @@ -273,9 +273,9 @@ class IonCacheGetProperty : public IonCache bool allowGetters() const { return u.getprop.allowGetters; } bool attachReadSlot(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder, - const Shape *shape); + HandleShape shape); bool attachCallGetter(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder, - const Shape *shape, + HandleShape shape, const SafepointIndex *safepointIndex, void *returnAddr); }; @@ -305,8 +305,8 @@ class IonCacheSetProperty : public IonCache bool attachNativeExisting(JSContext *cx, IonScript *ion, HandleObject obj, HandleShape shape); bool attachSetterCall(JSContext *cx, IonScript *ion, HandleObject obj, HandleObject holder, HandleShape shape, void *returnAddr); - bool attachNativeAdding(JSContext *cx, IonScript *ion, JSObject *obj, const Shape *oldshape, - const Shape *newshape, const Shape *propshape); + bool attachNativeAdding(JSContext *cx, IonScript *ion, JSObject *obj, HandleShape oldshape, + HandleShape newshape, HandleShape propshape); }; class IonCacheGetElement : public IonCache @@ -412,7 +412,7 @@ class IonCacheName : public IonCache } bool attach(JSContext *cx, IonScript *ion, HandleObject scopeChain, HandleObject obj, - Shape *shape); + HandleShape shape); }; bool diff --git a/js/src/ion/MIR.h b/js/src/ion/MIR.h index 429184f01a4..af52ba53cb6 100644 --- a/js/src/ion/MIR.h +++ b/js/src/ion/MIR.h @@ -4455,8 +4455,8 @@ class MBindNameCache : public MUnaryInstruction, public SingleObjectPolicy { - PropertyName *name_; - JSScript *script_; + CompilerRootPropertyName name_; + CompilerRootScript script_; jsbytecode *pc_; MBindNameCache(MDefinition *scopeChain, PropertyName *name, JSScript *script, jsbytecode *pc) @@ -4495,10 +4495,10 @@ class MGuardShape : public MUnaryInstruction, public SingleObjectPolicy { - const Shape *shape_; + CompilerRootShape shape_; BailoutKind bailoutKind_; - MGuardShape(MDefinition *obj, const Shape *shape, BailoutKind bailoutKind) + MGuardShape(MDefinition *obj, UnrootedShape shape, BailoutKind bailoutKind) : MUnaryInstruction(obj), shape_(shape), bailoutKind_(bailoutKind) @@ -4511,7 +4511,7 @@ class MGuardShape public: INSTRUCTION_HEADER(GuardShape) - static MGuardShape *New(MDefinition *obj, const Shape *shape, BailoutKind bailoutKind) { + static MGuardShape *New(MDefinition *obj, UnrootedShape shape, BailoutKind bailoutKind) { return new MGuardShape(obj, shape, bailoutKind); } @@ -4521,7 +4521,7 @@ class MGuardShape MDefinition *obj() const { return getOperand(0); } - const Shape *shape() const { + const UnrootedShape shape() const { return shape_; } BailoutKind bailoutKind() const { diff --git a/js/src/ion/VMFunctions.cpp b/js/src/ion/VMFunctions.cpp index 68bf284c9c6..586099bdcb3 100644 --- a/js/src/ion/VMFunctions.cpp +++ b/js/src/ion/VMFunctions.cpp @@ -142,7 +142,7 @@ InitProp(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue v if (name == cx->names().proto) return baseops::SetPropertyHelper(cx, obj, obj, id, 0, &rval, false); - return !!DefineNativeProperty(cx, obj, id, rval, NULL, NULL, JSPROP_ENUMERATE, 0, 0, 0); + return DefineNativeProperty(cx, obj, id, rval, NULL, NULL, JSPROP_ENUMERATE, 0, 0, 0); } template diff --git a/js/src/ion/shared/Assembler-shared.h b/js/src/ion/shared/Assembler-shared.h index d00494bf9d1..43ba1e5c707 100644 --- a/js/src/ion/shared/Assembler-shared.h +++ b/js/src/ion/shared/Assembler-shared.h @@ -98,6 +98,12 @@ struct ImmGCPtr explicit ImmGCPtr(const gc::Cell *ptr) : value(reinterpret_cast(ptr)) { } + + // ImmGCPtr is rooted so we can convert safely directly from Unrooted. + template + explicit ImmGCPtr(Unrooted ptr) + : value(reinterpret_cast(static_cast(ptr))) + { } }; // Specifies a hardcoded, absolute address. diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index d26a2f9fd3a..94412b96f66 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3829,8 +3829,8 @@ DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue val JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); if (flags != 0 && obj->isNative()) { - return !!DefineNativeProperty(cx, obj, id, value, getter, setter, - attrs, flags, tinyid); + return DefineNativeProperty(cx, obj, id, value, getter, setter, + attrs, flags, tinyid); } return JSObject::defineGeneric(cx, obj, id, value, getter, setter, attrs); } @@ -4477,15 +4477,15 @@ JS_DeleteProperty(JSContext *cx, JSObject *objArg, const char *name) return JS_DeleteProperty2(cx, objArg, name, &junk); } -static Shape * +static UnrootedShape LastConfigurableShape(JSObject *obj) { for (Shape::Range r(obj->lastProperty()->all()); !r.empty(); r.popFront()) { - Shape *shape = &r.front(); + UnrootedShape shape = &r.front(); if (shape->configurable()) return shape; } - return NULL; + return UnrootedShape(NULL); } JS_PUBLIC_API(void) @@ -4502,18 +4502,20 @@ JS_ClearNonGlobalObject(JSContext *cx, JSObject *objArg) return; /* Remove all configurable properties from obj. */ - while (Shape *shape = LastConfigurableShape(obj)) { + RootedShape shape(cx); + while ((shape = LastConfigurableShape(obj))) { if (!obj->removeProperty(cx, shape->propid())) return; } /* Set all remaining writable plain data properties to undefined. */ for (Shape::Range r(obj->lastProperty()->all()); !r.empty(); r.popFront()) { - Shape *shape = &r.front(); + UnrootedShape shape = &r.front(); if (shape->isDataDescriptor() && shape->writable() && shape->hasDefaultSetter() && - shape->hasSlot()) { + shape->hasSlot()) + { obj->nativeSetSlot(shape->slot(), UndefinedValue()); } } @@ -4556,7 +4558,7 @@ JS_Enumerate(JSContext *cx, JSObject *objArg) * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's * prop_iterator_class somehow... * + preserve the obj->enumerate API while optimizing the native object case - * + native case here uses a Shape *, but that iterates in reverse! + * + native case here uses a JSShape *, but that iterates in reverse! * + so we make non-native match, by reverse-iterating after JS_Enumerating */ const uint32_t JSSLOT_ITER_INDEX = 0; @@ -4588,7 +4590,7 @@ prop_iter_trace(JSTracer *trc, RawObject obj) * barrier here because the pointer is updated via setPrivate, which * always takes a barrier. */ - Shape *tmp = (Shape *)pdata; + UnrootedShape tmp = static_cast(pdata); MarkShapeUnbarriered(trc, &tmp, "prop iter shape"); obj->setPrivateUnbarriered(tmp); } else { @@ -4653,18 +4655,15 @@ JS_NextProperty(JSContext *cx, JSObject *iterobjArg, jsid *idp) { RootedObject iterobj(cx, iterobjArg); AutoAssertNoGC nogc; - int32_t i; - Shape *shape; - JSIdArray *ida; AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, iterobj); - i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32(); + int32_t i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32(); if (i < 0) { /* Native case: private data is a property tree node pointer. */ JS_ASSERT(iterobj->getParent()->isNative()); - shape = (Shape *) iterobj->getPrivate(); + UnrootedShape shape = static_cast(iterobj->getPrivate()); while (shape->previous() && !shape->enumerable()) shape = shape->previous(); @@ -4673,12 +4672,12 @@ JS_NextProperty(JSContext *cx, JSObject *iterobjArg, jsid *idp) JS_ASSERT(shape->isEmptyShape()); *idp = JSID_VOID; } else { - iterobj->setPrivateGCThing(const_cast(shape->previous().get())); + iterobj->setPrivateGCThing(const_cast(shape->previous().get())); *idp = shape->propid(); } } else { /* Non-native case: use the ida enumerated when iterobj was created. */ - ida = (JSIdArray *) iterobj->getPrivate(); + JSIdArray *ida = (JSIdArray *) iterobj->getPrivate(); JS_ASSERT(i <= ida->length); STATIC_ASSUME(i <= ida->length); if (i == 0) { diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 3a74cdd3d70..18fffd6dcfc 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -206,14 +206,14 @@ js::StringIsArrayIndex(JSLinearString *str, uint32_t *indexp) return false; } -Shape * +UnrootedShape js::GetDenseArrayShape(JSContext *cx, HandleObject globalObj) { JS_ASSERT(globalObj); JSObject *proto = globalObj->global().getOrCreateArrayPrototype(cx); if (!proto) - return NULL; + return UnrootedShape(NULL); return EmptyShape::getInitialShape(cx, &ArrayClass, proto, proto->getParent(), gc::FINALIZE_OBJECT0); @@ -265,7 +265,7 @@ JSObject::arrayGetOwnDataElement(JSContext *cx, size_t i, Value *vp) if (!IndexToId(cx, i, &id)) return false; - Shape *shape = nativeLookup(cx, id); + UnrootedShape shape = nativeLookup(cx, id); if (!shape || !shape->isDataDescriptor()) vp->setMagic(JS_ARRAY_HOLE); else @@ -1254,8 +1254,8 @@ AddLengthProperty(JSContext *cx, HandleObject obj) if (!obj->allocateSlowArrayElements(cx)) return false; - return obj->addProperty(cx, lengthId, array_length_getter, array_length_setter, - SHAPE_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0); + return JSObject::addProperty(cx, obj, lengthId, array_length_getter, array_length_setter, + SHAPE_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0); } /* @@ -1294,27 +1294,29 @@ JSObject::makeDenseArraySlow(JSContext *cx, HandleObject obj) * on error. This is gross, but a better way is not obvious. Note: the * exact contents of the array are not preserved on error. */ - js::Shape *oldShape = obj->lastProperty(); + RootedShape oldShape(cx, obj->lastProperty()); /* Create a native scope. */ - gc::AllocKind kind = obj->getAllocKind(); - Shape *shape = EmptyShape::getInitialShape(cx, &SlowArrayClass, obj->getProto(), - oldShape->getObjectParent(), kind); - if (!shape) - return false; + { + gc::AllocKind kind = obj->getAllocKind(); + UnrootedShape shape = EmptyShape::getInitialShape(cx, &SlowArrayClass, obj->getProto(), + oldShape->getObjectParent(), kind); + if (!shape) + return false; - /* - * In case an incremental GC is already running, we need to write barrier - * the elements before (temporarily) destroying them. - * - * Note: this has to happen after getInitialShape (which can trigger - * incremental GC) and *before* we overwrite shape, making us no longer a - * dense array. - */ - if (obj->compartment()->needsBarrier()) - obj->prepareElementRangeForOverwrite(0, arrayInitialized); + /* + * In case an incremental GC is already running, we need to write barrier + * the elements before (temporarily) destroying them. + * + * Note: this has to happen after getInitialShape (which can trigger + * incremental GC) and *before* we overwrite shape, making us no longer a + * dense array. + */ + if (obj->compartment()->needsBarrier()) + obj->prepareElementRangeForOverwrite(0, arrayInitialized); - obj->shape_ = shape; + obj->shape_ = shape; + } /* Reset to an empty dense array. */ obj->elements = emptyObjectElements; diff --git a/js/src/jsarray.h b/js/src/jsarray.h index 025b96185bb..522b47e0184 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -76,7 +76,7 @@ extern JSObject * NewSlowEmptyArray(JSContext *cx); /* Get the common shape used by all dense arrays with a prototype at globalObj. */ -extern Shape * +extern UnrootedShape GetDenseArrayShape(JSContext *cx, HandleObject globalObj); extern JSBool diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp index d83588cae43..e8cec4c9ac8 100644 --- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -428,6 +428,7 @@ template bool js::XDRAtom(XDRState *xdr, MutableHandleAtom atomp) { + AssertCanGC(); if (mode == XDR_ENCODE) { uint32_t nchars = atomp->length(); if (!xdr->codeUint32(&nchars)) diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 5757b4486e2..176a068372e 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -573,7 +573,7 @@ js::ReportUsageError(JSContext *cx, HandleObject callee, const char *msg) { const char *usageStr = "usage"; PropertyName *usageAtom = Atomize(cx, usageStr, strlen(usageStr))->asPropertyName(); - DebugOnly shape = callee->nativeLookup(cx, NameToId(usageAtom)); + DebugOnly shape = static_cast(callee->nativeLookup(cx, NameToId(usageAtom))); JS_ASSERT(!shape->configurable()); JS_ASSERT(!shape->writable()); JS_ASSERT(shape->hasDefaultGetter()); diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 742b0ccf97e..591ecb3dd31 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -317,7 +317,7 @@ class NewObjectCache inline void fillType(EntryIndex entry, Class *clasp, js::types::TypeObject *type, gc::AllocKind kind, JSObject *obj); /* Invalidate any entries which might produce an object with shape/proto. */ - void invalidateEntriesForShape(JSContext *cx, Shape *shape, JSObject *proto); + void invalidateEntriesForShape(JSContext *cx, HandleShape shape, HandleObject proto); private: inline bool lookup(Class *clasp, gc::Cell *key, gc::AllocKind kind, EntryIndex *pentry); diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 5889ae7c968..b3a175bd15f 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -798,7 +798,7 @@ JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp, /* This all should be reworked to avoid requiring JSScopeProperty types. */ static JSBool -GetPropertyDesc(JSContext *cx, JSObject *obj_, Shape *shape, JSPropertyDesc *pd) +GetPropertyDesc(JSContext *cx, JSObject *obj_, HandleShape shape, JSPropertyDesc *pd) { assertSameCompartment(cx, obj_); pd->id = IdToJsval(shape->propid()); @@ -901,7 +901,7 @@ JS_GetPropertyDescArray(JSContext *cx, JSObject *obj_, JSPropertyDescArray *pda) goto bad; if (!js_AddRoot(cx, &pd[i].value, NULL)) goto bad; - Shape *shape = const_cast(&r.front()); + RootedShape shape(cx, const_cast(&r.front())); if (!GetPropertyDesc(cx, obj, shape, &pd[i])) goto bad; if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL)) diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 1b88af0c706..889775665f1 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -256,7 +256,7 @@ JS_WrapAutoIdVector(JSContext *cx, js::AutoIdVector &props) JS_FRIEND_API(void) JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape) { - MarkCycleCollectorChildren(trc, (Shape *)shape); + MarkCycleCollectorChildren(trc, static_cast(shape)); } static bool @@ -905,7 +905,7 @@ js::IncrementalReferenceBarrier(void *ptr) else if (kind == JSTRACE_SCRIPT) JSScript::writeBarrierPre(reinterpret_cast(ptr)); else if (kind == JSTRACE_SHAPE) - Shape::writeBarrierPre((Shape *) ptr); + Shape::writeBarrierPre(reinterpret_cast(ptr)); else if (kind == JSTRACE_BASE_SHAPE) BaseShape::writeBarrierPre(reinterpret_cast(ptr)); else if (kind == JSTRACE_TYPE_OBJECT) diff --git a/js/src/jsgcinlines.h b/js/src/jsgcinlines.h index e68f8c5242e..bd61c02dee1 100644 --- a/js/src/jsgcinlines.h +++ b/js/src/jsgcinlines.h @@ -595,7 +595,7 @@ js_NewGCScript(JSContext *cx) return js::gc::NewGCThing(cx, js::gc::FINALIZE_SCRIPT, sizeof(JSScript)); } -inline js::Shape * +inline js::UnrootedShape js_NewGCShape(JSContext *cx) { return js::gc::NewGCThing(cx, js::gc::FINALIZE_SHAPE, sizeof(js::Shape)); diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 6edf697f0cb..9ef2d2f3c13 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -807,20 +807,22 @@ HeapTypeSet::addFilterPrimitives(JSContext *cx, TypeSet *target) } /* If id is a normal slotful 'own' property of an object, get its shape. */ -static inline Shape * -GetSingletonShape(JSContext *cx, HandleObject obj, jsid id) +static inline UnrootedShape +GetSingletonShape(JSContext *cx, RawObject obj, RawId id) { + AssertCanGC(); if (!obj->isNative()) - return NULL; - Shape *shape = obj->nativeLookup(cx, id); + return UnrootedShape(NULL); + UnrootedShape shape = DropUnrooted(obj)->nativeLookup(cx, DropUnrooted(id)); if (shape && shape->hasDefaultGetter() && shape->hasSlot()) return shape; - return NULL; + return UnrootedShape(NULL); } void ScriptAnalysis::pruneTypeBarriers(JSContext *cx, uint32_t offset) { + AssertCanGC(); TypeBarrier **pbarrier = &getCode(offset).typeBarriers; while (*pbarrier) { TypeBarrier *barrier = *pbarrier; @@ -831,8 +833,7 @@ ScriptAnalysis::pruneTypeBarriers(JSContext *cx, uint32_t offset) } if (barrier->singleton) { JS_ASSERT(barrier->type.isPrimitive(JSVAL_TYPE_UNDEFINED)); - RootedObject barrierSingleton(cx, barrier->singleton); - Shape *shape = GetSingletonShape(cx, barrierSingleton, barrier->singletonId); + UnrootedShape shape = GetSingletonShape(cx, barrier->singleton, barrier->singletonId); if (shape && !barrier->singleton->nativeGetSlot(shape->slot()).isUndefined()) { /* * When we analyzed the script the singleton had an 'own' @@ -1674,6 +1675,7 @@ class TypeConstraintFreezeObjectFlags : public TypeConstraint void newObjectState(JSContext *cx, TypeObject *object, bool force) { + AutoAssertNoGC nogc; if (!marked && (object->hasAnyFlags(flags) || (!flags && force))) { marked = true; cx->compartment->types.addPendingRecompile(cx, info); @@ -2548,6 +2550,7 @@ TypeCompartment::nukeTypes(FreeOp *fop) void TypeCompartment::addPendingRecompile(JSContext *cx, const RecompileInfo &info) { + AutoAssertNoGC nogc; CompilerOutput *co = info.compilerOutput(cx); if (co->pendingRecompilation) @@ -3027,13 +3030,14 @@ struct types::ObjectTableKey ((uint32_t)obj->getTaggedProto().toWord() >> 2)); } - static inline bool match(const ObjectTableKey &v, JSObject *obj) { + static inline bool match(const ObjectTableKey &v, RawObject obj) { if (obj->slotSpan() != v.nslots || obj->numFixedSlots() != v.nfixed || obj->getTaggedProto() != v.proto) { return false; } - Shape *shape = obj->lastProperty(); + UnrootedShape shape = obj->lastProperty(); + obj = NULL; while (!shape->isEmptyShape()) { if (shape->propid() != v.ids[shape->slot()]) return false; @@ -3075,7 +3079,7 @@ TypeCompartment::fixObjectType(JSContext *cx, HandleObject obj) return; ObjectTypeTable::AddPtr p = objectTypeTable->lookupForAdd(obj.get()); - Shape *baseShape = obj->lastProperty(); + RootedShape baseShape(cx, obj->lastProperty()); if (p) { /* The lookup ensures the shape matches, now check that the types match. */ @@ -3086,7 +3090,7 @@ TypeCompartment::fixObjectType(JSContext *cx, HandleObject obj) if (NumberTypes(ntype, types[i])) { if (types[i].isPrimitive(JSVAL_TYPE_INT32)) { types[i] = Type::DoubleType(); - Shape *shape = baseShape; + RootedShape shape(cx, baseShape); while (!shape->isEmptyShape()) { if (shape->slot() == i) { Type type = Type::DoubleType(); @@ -3127,7 +3131,7 @@ TypeCompartment::fixObjectType(JSContext *cx, HandleObject obj) return; } - Shape *shape = baseShape; + RootedShape shape(cx, baseShape); while (!shape->isEmptyShape()) { ids[shape->slot()] = shape->propid(); types[shape->slot()] = GetValueTypeForTable(cx, obj->getSlot(shape->slot())); @@ -3194,7 +3198,7 @@ TypeObject::getFromPrototypes(JSContext *cx, jsid id, TypeSet *types, bool force } static inline void -UpdatePropertyType(JSContext *cx, TypeSet *types, HandleObject obj, Shape *shape, bool force) +UpdatePropertyType(JSContext *cx, TypeSet *types, RawObject obj, UnrootedShape shape, bool force) { types->setOwnProperty(cx, false); if (!shape->writable()) @@ -3239,14 +3243,14 @@ TypeObject::addProperty(JSContext *cx, jsid id, Property **pprop) RootedObject rSingleton(cx, singleton); if (JSID_IS_VOID(id)) { /* Go through all shapes on the object to get integer-valued properties. */ - Shape *shape = singleton->lastProperty(); + UnrootedShape shape = singleton->lastProperty(); while (!shape->isEmptyShape()) { if (JSID_IS_VOID(MakeTypeId(cx, shape->propid()))) UpdatePropertyType(cx, &base->types, rSingleton, shape, true); shape = shape->previous(); } } else if (!JSID_IS_EMPTY(id) && singleton->isNative()) { - Shape *shape = singleton->nativeLookup(cx, id); + UnrootedShape shape = singleton->nativeLookup(cx, id); if (shape) UpdatePropertyType(cx, &base->types, rSingleton, shape, false); } @@ -3278,7 +3282,7 @@ TypeObject::addDefiniteProperties(JSContext *cx, HandleObject obj) /* Mark all properties of obj as definite properties of this type. */ AutoEnterTypeInference enter(cx); - Shape *shape = obj->lastProperty(); + RootedShape shape(cx, obj->lastProperty()); while (!shape->isEmptyShape()) { jsid id = MakeTypeId(cx, shape->propid()); if (!JSID_IS_VOID(id) && obj->isFixedSlot(shape->slot()) && @@ -3306,7 +3310,7 @@ TypeObject::matchDefiniteProperties(HandleObject obj) unsigned slot = prop->types.definiteSlot(); bool found = false; - Shape *shape = obj->lastProperty(); + UnrootedShape shape = obj->lastProperty(); while (!shape->isEmptyShape()) { if (shape->slot() == slot && shape->propid() == prop->id) { found = true; @@ -3325,6 +3329,7 @@ TypeObject::matchDefiniteProperties(HandleObject obj) inline void InlineAddTypeProperty(JSContext *cx, TypeObject *obj, jsid id, Type type) { + AssertCanGC(); JS_ASSERT(id == MakeTypeId(cx, id)); AutoEnterTypeInference enter(cx); @@ -3353,6 +3358,7 @@ TypeObject::addPropertyType(JSContext *cx, jsid id, const Value &value) void TypeObject::addPropertyType(JSContext *cx, const char *name, Type type) { + AssertCanGC(); jsid id = JSID_VOID; if (name) { JSAtom *atom = Atomize(cx, name, strlen(name)); @@ -3387,6 +3393,8 @@ TypeObject::markPropertyConfigured(JSContext *cx, jsid id) void TypeObject::markStateChange(JSContext *cx) { + AutoAssertNoGC nogc; + if (unknownProperties()) return; @@ -5020,6 +5028,8 @@ CheckNewScriptProperties(JSContext *cx, HandleTypeObject type, JSFunction *fun) return; } + AutoAssertNoGC nogc; + type->newScript->fun = fun; type->newScript->allocKind = kind; type->newScript->shape = baseobj->lastProperty(); @@ -5828,6 +5838,7 @@ JSObject::setNewTypeUnknown(JSContext *cx) TypeObject * JSCompartment::getNewType(JSContext *cx, TaggedProto proto_, JSFunction *fun_, bool isDOM) { + AssertCanGC(); JS_ASSERT_IF(fun_, proto_.isObject()); JS_ASSERT_IF(proto_.isObject(), cx->compartment == proto_.toObject()->compartment()); diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index da17b3e7c33..15a5b4da327 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -275,6 +275,7 @@ TypeFlagPrimitive(TypeFlags flags) inline jsid MakeTypeId(JSContext *cx, jsid id) { + AutoAssertNoGC nogc; JS_ASSERT(!JSID_IS_EMPTY(id)); /* @@ -546,6 +547,8 @@ TypeMonitorCall(JSContext *cx, const js::CallArgs &args, bool constructing) inline bool TrackPropertyTypes(JSContext *cx, HandleObject obj, jsid id) { + AutoAssertNoGC nogc; + if (!cx->typeInferenceEnabled() || obj->hasLazyType() || obj->type()->unknownProperties()) return false; @@ -559,6 +562,7 @@ TrackPropertyTypes(JSContext *cx, HandleObject obj, jsid id) inline void AddTypePropertyId(JSContext *cx, HandleObject obj, jsid id, Type type) { + AssertCanGC(); if (cx->typeInferenceEnabled()) id = MakeTypeId(cx, id); if (TrackPropertyTypes(cx, obj, id)) @@ -568,6 +572,7 @@ AddTypePropertyId(JSContext *cx, HandleObject obj, jsid id, Type type) inline void AddTypePropertyId(JSContext *cx, HandleObject obj, jsid id, const Value &value) { + AssertCanGC(); if (cx->typeInferenceEnabled()) id = MakeTypeId(cx, id); if (TrackPropertyTypes(cx, obj, id)) @@ -577,6 +582,7 @@ AddTypePropertyId(JSContext *cx, HandleObject obj, jsid id, const Value &value) inline void AddTypeProperty(JSContext *cx, TypeObject *obj, const char *name, Type type) { + AssertCanGC(); if (cx->typeInferenceEnabled() && !obj->unknownProperties()) obj->addPropertyType(cx, name, type); } @@ -584,6 +590,7 @@ AddTypeProperty(JSContext *cx, TypeObject *obj, const char *name, Type type) inline void AddTypeProperty(JSContext *cx, TypeObject *obj, const char *name, const Value &value) { + AssertCanGC(); if (cx->typeInferenceEnabled() && !obj->unknownProperties()) obj->addPropertyType(cx, name, value); } @@ -629,8 +636,9 @@ MarkTypePropertyConfigured(JSContext *cx, HandleObject obj, jsid id) /* Mark a state change on a particular object. */ inline void -MarkObjectStateChange(JSContext *cx, HandleObject obj) +MarkObjectStateChange(JSContext *cx, RawObject obj) { + AutoAssertNoGC nogc; if (cx->typeInferenceEnabled() && !obj->hasLazyType() && !obj->type()->unknownProperties()) obj->type()->markStateChange(cx); } @@ -1565,6 +1573,7 @@ TypeObject::getProperty(JSContext *cx, jsid id, bool own) inline HeapTypeSet * TypeObject::maybeGetProperty(JSContext *cx, jsid id) { + AutoAssertNoGC nogc; JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id)); JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == MakeTypeId(cx, id)); JS_ASSERT(!unknownProperties()); diff --git a/js/src/jsinterpinlines.h b/js/src/jsinterpinlines.h index a5d78ae15e4..25e55caa70e 100644 --- a/js/src/jsinterpinlines.h +++ b/js/src/jsinterpinlines.h @@ -174,15 +174,16 @@ ValuePropertyBearer(JSContext *cx, StackFrame *fp, HandleValue v, int spindex) } inline bool -NativeGet(JSContext *cx, Handle obj, Handle pobj, Shape *shape, +NativeGet(JSContext *cx, Handle obj, Handle pobj, Shape *shapeArg, unsigned getHow, MutableHandleValue vp) { - if (shape->isDataDescriptor() && shape->hasDefaultGetter()) { + if (shapeArg->isDataDescriptor() && shapeArg->hasDefaultGetter()) { /* Fast path for Object instance properties. */ - JS_ASSERT(shape->hasSlot()); - vp.set(pobj->nativeGetSlot(shape->slot())); + JS_ASSERT(shapeArg->hasSlot()); + vp.set(pobj->nativeGetSlot(shapeArg->slot())); } else { - if (!js_NativeGet(cx, obj, pobj, shape, getHow, vp.address())) + RootedShape shape(cx, shapeArg); + if (!js_NativeGet(cx, obj, pobj, shape, getHow, vp)) return false; } return true; diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 870ec51c0bb..ae84679a377 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -431,8 +431,8 @@ NativeIterator::allocateIterator(JSContext *cx, uint32_t slength, const AutoIdVe size_t plength = props.length(); NativeIterator *ni = (NativeIterator *) cx->malloc_(sizeof(NativeIterator) - + plength * sizeof(JSString *) - + slength * sizeof(Shape *)); + + plength * sizeof(RawString) + + slength * sizeof(RawShape)); if (!ni) return NULL; AutoValueVector strings(cx); @@ -602,7 +602,7 @@ js::GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleVa return true; } - Vector shapes(cx); + Vector shapes(cx); uint32_t key = 0; bool keysOnly = (flags == JSITER_ENUMERATE); @@ -651,6 +651,7 @@ js::GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleVa * currently active. */ { + AutoAssertNoGC nogc; RawObject pobj = obj; do { if (!pobj->isNative() || @@ -660,9 +661,9 @@ js::GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleVa shapes.clear(); goto miss; } - Shape *shape = pobj->lastProperty(); + RawShape shape = pobj->lastProperty(); key = (key + (key << 16)) ^ (uintptr_t(shape) >> 3); - if (!shapes.append((Shape *) shape)) + if (!shapes.append(shape)) return false; pobj = pobj->getProto(); } while (pobj); diff --git a/js/src/jsmemorymetrics.cpp b/js/src/jsmemorymetrics.cpp index 03cef2b2b2b..a1878a5d325 100644 --- a/js/src/jsmemorymetrics.cpp +++ b/js/src/jsmemorymetrics.cpp @@ -197,7 +197,7 @@ StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKin } case JSTRACE_SHAPE: { - Shape *shape = static_cast(thing); + UnrootedShape shape = static_cast(thing); size_t propTableSize, kidsSize; shape->sizeOfExcludingThis(rtStats->mallocSizeOf, &propTableSize, &kidsSize); if (shape->inDictionary()) { diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 61c4fe960cb..572b0f85dfc 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1348,7 +1348,7 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval); } - if (!js_NativeGet(cx, obj, obj2, shape, 0, v.address())) + if (!js_NativeGet(cx, obj, obj2, shape, 0, &v)) return JS_FALSE; } @@ -1880,11 +1880,11 @@ JSObject::sealOrFreeze(JSContext *cx, HandleObject obj, ImmutabilityType it) * generic path below then any non-empty object will be converted to * dictionary mode. */ - Shape *last = EmptyShape::getInitialShape(cx, obj->getClass(), - obj->getTaggedProto(), - obj->getParent(), - obj->getAllocKind(), - obj->lastProperty()->getObjectFlags()); + RootedShape last(cx, EmptyShape::getInitialShape(cx, obj->getClass(), + obj->getTaggedProto(), + obj->getParent(), + obj->getAllocKind(), + obj->lastProperty()->getObjectFlags())); if (!last) return false; @@ -2113,6 +2113,7 @@ static inline JSObject * NewObject(JSContext *cx, Class *clasp, types::TypeObject *type_, JSObject *parent, gc::AllocKind kind) { + AssertCanGC(); JS_ASSERT(clasp != &ArrayClass); JS_ASSERT_IF(clasp == &FunctionClass, kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind); @@ -2291,14 +2292,16 @@ js::NewReshapedObject(JSContext *cx, HandleTypeObject type, JSObject *parent, /* Get all the ids in the object, in order. */ js::AutoIdVector ids(cx); - for (unsigned i = 0; i <= shape->slot(); i++) { - if (!ids.append(JSID_VOID)) - return NULL; - } - js::Shape *nshape = shape; - while (!nshape->isEmptyShape()) { - ids[nshape->slot()] = nshape->propid(); - nshape = nshape->previous(); + { + for (unsigned i = 0; i <= shape->slot(); i++) { + if (!ids.append(JSID_VOID)) + return NULL; + } + UnrootedShape nshape = shape; + while (!nshape->isEmptyShape()) { + ids[nshape->slot()] = nshape->propid(); + nshape = nshape->previous(); + } } /* Construct the new shape. */ @@ -2340,9 +2343,10 @@ CreateThisForFunctionWithType(JSContext *cx, HandleTypeObject type, JSObject *pa */ gc::AllocKind kind = type->newScript->allocKind; RootedObject res(cx, NewObjectWithType(cx, type, parent, kind)); - if (res) - JS_ALWAYS_TRUE(JSObject::setLastProperty(cx, res, - (Shape *) type->newScript->shape.get())); + if (res) { + RootedShape shape(cx, type->newScript->shape); + JS_ALWAYS_TRUE(JSObject::setLastProperty(cx, res, shape)); + } return res; } @@ -2550,9 +2554,12 @@ JS_CopyPropertiesFrom(JSContext *cx, JSObject *targetArg, JSObject *obj) return false; } + RootedShape shape(cx); + RootedValue v(cx); + RootedId id(cx); size_t n = shapes.length(); while (n > 0) { - Shape *shape = shapes[--n]; + shape = shapes[--n]; unsigned attrs = shape->attributes(); PropertyOp getter = shape->getter(); StrictPropertyOp setter = shape->setter(); @@ -2561,10 +2568,10 @@ JS_CopyPropertiesFrom(JSContext *cx, JSObject *targetArg, JSObject *obj) return false; if ((attrs & JSPROP_SETTER) && !cx->compartment->wrap(cx, &setter)) return false; - RootedValue v(cx, shape->hasSlot() ? obj->getSlot(shape->slot()) : UndefinedValue()); + v = shape->hasSlot() ? obj->getSlot(shape->slot()) : UndefinedValue(); if (!cx->compartment->wrap(cx, v.address())) return false; - Rooted id(cx, shape->propid()); + id = shape->propid(); if (!JSObject::defineGeneric(cx, target, id, v, getter, setter, attrs)) return false; } @@ -2648,15 +2655,15 @@ struct JSObject::TradeGutsReserved { Vector bvals; int newafixed; int newbfixed; - Shape *newashape; - Shape *newbshape; + RootedShape newashape; + RootedShape newbshape; HeapSlot *newaslots; HeapSlot *newbslots; TradeGutsReserved(JSContext *cx) : avals(cx), bvals(cx), newafixed(0), newbfixed(0), - newashape(NULL), newbshape(NULL), + newashape(cx), newbshape(cx), newaslots(NULL), newbslots(NULL) {} @@ -2673,6 +2680,7 @@ bool JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &reserved) { + AssertCanGC(); JS_ASSERT(a->compartment() == b->compartment()); AutoCompartment ac(cx, a); @@ -2782,6 +2790,7 @@ JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b, void JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &reserved) { + AutoAssertNoGC nogc; JS_ASSERT(a->compartment() == b->compartment()); JS_ASSERT(a->isFunction() == b->isFunction()); @@ -2956,11 +2965,10 @@ DefineStandardSlot(JSContext *cx, HandleObject obj, JSProtoKey key, JSAtom *atom JS_ASSERT(obj->isGlobal()); JS_ASSERT(obj->isNative()); - Shape *shape = obj->nativeLookup(cx, id); - if (!shape) { + if (!obj->nativeLookup(cx, id)) { uint32_t slot = 2 * JSProto_LIMIT + key; obj->setReservedSlot(slot, v); - if (!obj->addProperty(cx, id, JS_PropertyStub, JS_StrictPropertyStub, slot, attrs, 0, 0)) + if (!JSObject::addProperty(cx, obj, id, JS_PropertyStub, JS_StrictPropertyStub, slot, attrs, 0, 0)) return false; AddTypePropertyId(cx, obj, id, v); @@ -3234,7 +3242,7 @@ JSObject::updateSlotsForSpan(JSContext *cx, HandleObject obj, size_t oldSpan, si } /* static */ bool -JSObject::setLastProperty(JSContext *cx, HandleObject obj, js::Shape *shape) +JSObject::setLastProperty(JSContext *cx, HandleObject obj, HandleShape shape) { JS_ASSERT(!obj->inDictionaryMode()); JS_ASSERT(!shape->inDictionary()); @@ -3689,31 +3697,32 @@ js_FindClassObject(JSContext *cx, JSProtoKey protoKey, MutableHandleValue vp, Cl return true; } -bool -JSObject::allocSlot(JSContext *cx, uint32_t *slotp) +/* static */ bool +JSObject::allocSlot(JSContext *cx, HandleObject obj, uint32_t *slotp) { - uint32_t slot = slotSpan(); - JS_ASSERT(slot >= JSSLOT_FREE(getClass())); + AssertCanGC(); + uint32_t slot = obj->slotSpan(); + JS_ASSERT(slot >= JSSLOT_FREE(obj->getClass())); /* * If this object is in dictionary mode, try to pull a free slot from the * shape table's slot-number freelist. */ - if (inDictionaryMode()) { - ShapeTable &table = lastProperty()->table(); + if (obj->inDictionaryMode()) { + ShapeTable &table = obj->lastProperty()->table(); uint32_t last = table.freelist; if (last != SHAPE_INVALID_SLOT) { #ifdef DEBUG JS_ASSERT(last < slot); - uint32_t next = getSlot(last).toPrivateUint32(); + uint32_t next = obj->getSlot(last).toPrivateUint32(); JS_ASSERT_IF(next != SHAPE_INVALID_SLOT, next < slot); #endif *slotp = last; - const Value &vref = getSlot(last); + const Value &vref = obj->getSlot(last); table.freelist = vref.toPrivateUint32(); - setSlot(last, UndefinedValue()); + obj->setSlot(last, UndefinedValue()); return true; } } @@ -3725,8 +3734,7 @@ JSObject::allocSlot(JSContext *cx, uint32_t *slotp) *slotp = slot; - RootedObject self(cx, this); - if (inDictionaryMode() && !setSlotSpan(cx, self, slot + 1)) + if (obj->inDictionaryMode() && !setSlotSpan(cx, obj, slot + 1)) return false; return true; @@ -3758,13 +3766,12 @@ JSObject::freeSlot(uint32_t slot) } static bool -PurgeProtoChain(JSContext *cx, JSObject *obj_, jsid id_) +PurgeProtoChain(JSContext *cx, RawObject objArg, HandleId id) { - Shape *shape; - - RootedObject obj(cx, obj_); - RootedId id(cx, id_); + /* Root locally so we can re-assign. */ + RootedObject obj(cx, objArg); + RootedShape shape(cx); while (obj) { /* Lookups will not be cached through non-native protos. */ if (!obj->isNative()) @@ -3785,10 +3792,10 @@ PurgeProtoChain(JSContext *cx, JSObject *obj_, jsid id_) } bool -js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj_, jsid id_) +js_PurgeScopeChainHelper(JSContext *cx, HandleObject objArg, HandleId id) { - RootedObject obj(cx, obj_); - RootedId id(cx, id_); + /* Re-root locally so we can re-assign. */ + RootedObject obj(cx, objArg); JS_ASSERT(obj->isNative()); JS_ASSERT(obj->isDelegate()); @@ -3810,29 +3817,27 @@ js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj_, jsid id_) return true; } -Shape * -js_AddNativeProperty(JSContext *cx, HandleObject obj, jsid id_, +UnrootedShape +js_AddNativeProperty(JSContext *cx, HandleObject obj, HandleId id, PropertyOp getter, StrictPropertyOp setter, uint32_t slot, unsigned attrs, unsigned flags, int shortid) { - RootedId id(cx, id_); - /* * Purge the property cache of now-shadowed id in obj's scope chain. Do * this optimistically (assuming no failure below) before locking obj, so * we can lock the shadowed scope. */ if (!js_PurgeScopeChain(cx, obj, id)) - return NULL; + return UnrootedShape(NULL); - return obj->putProperty(cx, id, getter, setter, slot, attrs, flags, shortid); + return JSObject::putProperty(cx, obj, id, getter, setter, slot, attrs, flags, shortid); } JSBool baseops::DefineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue value, PropertyOp getter, StrictPropertyOp setter, unsigned attrs) { - return !!DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, 0, 0); + return DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, 0, 0); } JSBool @@ -3842,7 +3847,7 @@ baseops::DefineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleVa Rooted id(cx); if (index <= JSID_INT_MAX) { id = INT_TO_JSID(index); - return !!DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, 0, 0); + return DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, 0, 0); } AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); @@ -3850,7 +3855,7 @@ baseops::DefineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleVa if (!IndexToId(cx, index, id.address())) return false; - return !!DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, 0, 0); + return DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, 0, 0); } /* @@ -3878,7 +3883,7 @@ CallAddPropertyHook(JSContext *cx, Class *clasp, HandleObject obj, HandleShape s return true; } -Shape * +bool js::DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue value, PropertyOp getter, StrictPropertyOp setter, unsigned attrs, unsigned flags, int shortid, unsigned defineHow /* = 0 */) @@ -3908,7 +3913,7 @@ js::DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, HandleVal RootedObject pobj(cx); RootedShape prop(cx); if (!baseops::LookupProperty(cx, obj, id, &pobj, &prop)) - return NULL; + return false; if (prop && pobj == obj) { shape = prop; if (shape->isAccessorDescriptor()) { @@ -3921,7 +3926,7 @@ js::DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, HandleVal ? setter : shape->setter()); if (!shape) - return NULL; + return false; } else { shape = NULL; } @@ -3935,7 +3940,7 @@ js::DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, HandleVal */ if (!(defineHow & DNP_DONT_PURGE)) { if (!js_PurgeScopeChain(cx, obj, id)) - return NULL; + return false; } /* Use the object's class getter and setter by default. */ @@ -3956,10 +3961,10 @@ js::DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, HandleVal } if (!shape) { - shape = obj->putProperty(cx, id, getter, setter, SHAPE_INVALID_SLOT, - attrs, flags, shortid); + shape = JSObject::putProperty(cx, obj, id, getter, setter, SHAPE_INVALID_SLOT, + attrs, flags, shortid); if (!shape) - return NULL; + return false; } /* Store valueCopy before calling addProperty, in case the latter GC's. */ @@ -3968,7 +3973,7 @@ js::DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, HandleVal if (!CallAddPropertyHook(cx, clasp, obj, shape, value)) { obj->removeProperty(cx, id); - return NULL; + return false; } return shape; @@ -4051,7 +4056,7 @@ CallResolveOp(JSContext *cx, HandleObject obj, HandleId id, unsigned flags, objp.set(obj); } - Shape *shape; + UnrootedShape shape; if (!objp->nativeEmpty() && (shape = objp->nativeLookup(cx, id))) propp.set(shape); else @@ -4067,11 +4072,13 @@ LookupPropertyWithFlagsInline(JSContext *cx, HandleObject obj, HandleId id, unsi /* Search scopes starting with obj and following the prototype link. */ RootedObject current(cx, obj); while (true) { - Shape *shape = current->nativeLookup(cx, id); - if (shape) { - objp.set(current); - propp.set(shape); - return true; + { + UnrootedShape shape = current->nativeLookup(cx, id); + if (shape) { + objp.set(current); + propp.set(shape); + return true; + } } /* Try obj's class resolve hook if id was not found in obj's scope. */ @@ -4177,18 +4184,19 @@ js::LookupNameWithGlobalDefault(JSContext *cx, HandlePropertyName name, HandleOb } static JS_ALWAYS_INLINE JSBool -js_NativeGetInline(JSContext *cx, Handle receiver, JSObject *obj, JSObject *pobj, - Shape *shape, unsigned getHow, Value *vp) +js_NativeGetInline(JSContext *cx, Handle receiver, Handle obj, + Handle pobj, Handle shape, unsigned getHow, + MutableHandle vp) { JS_ASSERT(pobj->isNative()); if (shape->hasSlot()) { - *vp = pobj->nativeGetSlot(shape->slot()); - JS_ASSERT(!vp->isMagic()); + vp.set(pobj->nativeGetSlot(shape->slot())); + JS_ASSERT(!vp.isMagic()); JS_ASSERT_IF(!pobj->hasSingletonType() && shape->hasDefaultGetter(), - js::types::TypeHasProperty(cx, pobj->type(), shape->propid(), *vp)); + js::types::TypeHasProperty(cx, pobj->type(), shape->propid(), vp)); } else { - vp->setUndefined(); + vp.setUndefined(); } if (shape->hasDefaultGetter()) return true; @@ -4201,24 +4209,19 @@ js_NativeGetInline(JSContext *cx, Handle receiver, JSObject *obj, JSO code->accessGetter = true; } - Rooted shapeRoot(cx, shape); - RootedObject pobjRoot(cx, pobj); - RootedValue nvp(cx, *vp); - - if (!shape->get(cx, receiver, obj, pobj, &nvp)) + if (!shape->get(cx, receiver, obj, pobj, vp)) return false; /* Update slotful shapes according to the value produced by the getter. */ - if (shapeRoot->hasSlot() && pobjRoot->nativeContains(cx, shapeRoot)) - pobjRoot->nativeSetSlot(shapeRoot->slot(), nvp); + if (shape->hasSlot() && pobj->nativeContains(cx, shape)) + pobj->nativeSetSlot(shape->slot(), vp); - *vp = nvp; return true; } JSBool -js_NativeGet(JSContext *cx, Handle obj, Handle pobj, Shape *shape, - unsigned getHow, Value *vp) +js_NativeGet(JSContext *cx, Handle obj, Handle pobj, Handle shape, + unsigned getHow, MutableHandle vp) { return js_NativeGetInline(cx, obj, obj, pobj, shape, getHow, vp); } @@ -4358,7 +4361,7 @@ js_GetPropertyHelperInline(JSContext *cx, HandleObject obj, HandleObject receive cx->propertyCache().fill(cx, obj, obj2, shape); /* This call site is hot -- use the always-inlined variant of js_NativeGet(). */ - if (!js_NativeGetInline(cx, receiver, obj, obj2, shape, getHow, vp.address())) + if (!js_NativeGetInline(cx, receiver, obj, obj2, shape, getHow, vp)) return JS_FALSE; return JS_TRUE; @@ -4638,8 +4641,8 @@ baseops::SetPropertyHelper(JSContext *cx, HandleObject obj, HandleObject receive if (!js_PurgeScopeChain(cx, obj, id)) return JS_FALSE; - shape = obj->putProperty(cx, id, getter, setter, SHAPE_INVALID_SLOT, - attrs, flags, shortid); + shape = JSObject::putProperty(cx, obj, id, getter, setter, SHAPE_INVALID_SLOT, + attrs, flags, shortid); if (!shape) return JS_FALSE; @@ -4809,7 +4812,7 @@ baseops::DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, bool js::HasDataProperty(JSContext *cx, HandleObject obj, jsid id, Value *vp) { - if (Shape *shape = obj->nativeLookup(cx, id)) { + if (UnrootedShape shape = obj->nativeLookup(cx, id)) { if (shape->hasDefaultGetter() && shape->hasSlot()) { *vp = obj->nativeGetSlot(shape->slot()); return true; @@ -5158,7 +5161,7 @@ js_GetObjectSlotName(JSTracer *trc, char *buf, size_t bufsize) JSObject *obj = (JSObject *)trc->debugPrintArg; uint32_t slot = uint32_t(trc->debugPrintIndex); - Shape *shape; + UnrootedShape shape; if (obj->isNative()) { shape = obj->lastProperty(); while (shape && (!shape->hasSlot() || shape->slot() != slot)) @@ -5295,7 +5298,7 @@ DumpProperty(JSObject *obj, Shape &shape) jsid id = shape.propid(); uint8_t attrs = shape.attributes(); - fprintf(stderr, " ((Shape *) %p) ", (void *) &shape); + fprintf(stderr, " ((JSShape *) %p) ", (void *) &shape); if (attrs & JSPROP_ENUMERATE) fprintf(stderr, "enumerate "); if (attrs & JSPROP_READONLY) fprintf(stderr, "readonly "); if (attrs & JSPROP_PERMANENT) fprintf(stderr, "permanent "); @@ -5396,7 +5399,7 @@ JSObject::dump() if (obj->isNative()) { fprintf(stderr, "properties:\n"); - Vector props; + Vector props; for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront()) props.append(&r.front()); for (size_t i = props.length(); i-- != 0;) diff --git a/js/src/jsobj.h b/js/src/jsobj.h index fb3db097716..a45387159f9 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -21,9 +21,6 @@ #include "jsclass.h" #include "jsfriendapi.h" #include "jsinfer.h" -#include "jspubtd.h" -#include "jsprvtd.h" -#include "jslock.h" #include "gc/Barrier.h" #include "gc/Heap.h" @@ -38,6 +35,8 @@ class BaseProxyHandler; class CallObject; struct GCMarker; struct NativeIterator; +ForwardDeclare(Shape); +struct StackShape; namespace mjit { class Compiler; } @@ -280,10 +279,10 @@ struct JSObject : public js::ObjectImpl * Update the last property, keeping the number of allocated slots in sync * with the object's new slot span. */ - static bool setLastProperty(JSContext *cx, js::HandleObject obj, js::Shape *shape); + static bool setLastProperty(JSContext *cx, JS::HandleObject obj, js::HandleShape shape); /* As above, but does not change the slot span. */ - inline void setLastPropertyInfallible(js::Shape *shape); + inline void setLastPropertyInfallible(js::UnrootedShape shape); /* Make a non-array object with the specified initial state. */ static inline JSObject *create(JSContext *cx, @@ -726,7 +725,7 @@ struct JSObject : public js::ObjectImpl * after calling object-parameter-free shape methods, avoiding coupling * logic across the object vs. shape module wall. */ - bool allocSlot(JSContext *cx, uint32_t *slotp); + static bool allocSlot(JSContext *cx, JS::HandleObject obj, uint32_t *slotp); void freeSlot(uint32_t slot); public: @@ -744,7 +743,8 @@ struct JSObject : public js::ObjectImpl js::MutableHandleValue vp); private: - js::Shape *getChildProperty(JSContext *cx, js::Shape *parent, js::StackShape &child); + static js::UnrootedShape getChildProperty(JSContext *cx, JS::HandleObject obj, + js::HandleShape parent, js::StackShape &child); protected: /* @@ -754,11 +754,12 @@ struct JSObject : public js::ObjectImpl * 1. getter and setter must be normalized based on flags (see jsscope.cpp). * 2. !isExtensible() checking must be done by callers. */ - js::Shape *addPropertyInternal(JSContext *cx, jsid id, - JSPropertyOp getter, JSStrictPropertyOp setter, - uint32_t slot, unsigned attrs, - unsigned flags, int shortid, js::Shape **spp, - bool allowDictionary); + static js::UnrootedShape addPropertyInternal(JSContext *cx, + JS::HandleObject obj, JS::HandleId id, + JSPropertyOp getter, JSStrictPropertyOp setter, + uint32_t slot, unsigned attrs, + unsigned flags, int shortid, js::Shape **spp, + bool allowDictionary); private: bool toDictionaryMode(JSContext *cx); @@ -772,33 +773,38 @@ struct JSObject : public js::ObjectImpl public: /* Add a property whose id is not yet in this scope. */ - js::Shape *addProperty(JSContext *cx, jsid id, - JSPropertyOp getter, JSStrictPropertyOp setter, - uint32_t slot, unsigned attrs, - unsigned flags, int shortid, bool allowDictionary = true); + static js::UnrootedShape addProperty(JSContext *cx, JS::HandleObject, JS::HandleId id, + JSPropertyOp getter, JSStrictPropertyOp setter, + uint32_t slot, unsigned attrs, unsigned flags, + int shortid, bool allowDictionary = true); /* Add a data property whose id is not yet in this scope. */ - js::Shape *addDataProperty(JSContext *cx, jsid id, uint32_t slot, unsigned attrs) { + js::UnrootedShape addDataProperty(JSContext *cx, jsid id_, uint32_t slot, unsigned attrs) { JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); - return addProperty(cx, id, NULL, NULL, slot, attrs, 0, 0); + js::RootedObject self(cx, this); + js::RootedId id(cx, id_); + return addProperty(cx, self, id, NULL, NULL, slot, attrs, 0, 0); } /* Add or overwrite a property for id in this scope. */ - js::Shape *putProperty(JSContext *cx, jsid id, - JSPropertyOp getter, JSStrictPropertyOp setter, - uint32_t slot, unsigned attrs, - unsigned flags, int shortid); - inline js::Shape * - putProperty(JSContext *cx, js::PropertyName *name, - JSPropertyOp getter, JSStrictPropertyOp setter, - uint32_t slot, unsigned attrs, unsigned flags, int shortid) { - return putProperty(cx, js::NameToId(name), getter, setter, slot, attrs, flags, shortid); + static js::UnrootedShape putProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, + JSPropertyOp getter, JSStrictPropertyOp setter, + uint32_t slot, unsigned attrs, + unsigned flags, int shortid); + static js::UnrootedShape putProperty(JSContext *cx, JS::HandleObject obj, + js::PropertyName *name, + JSPropertyOp getter, JSStrictPropertyOp setter, + uint32_t slot, unsigned attrs, + unsigned flags, int shortid) + { + js::RootedId id(cx, js::NameToId(name)); + return putProperty(cx, obj, id, getter, setter, slot, attrs, flags, shortid); } /* Change the given property into a sibling with the same id in this scope. */ - static js::Shape *changeProperty(JSContext *cx, js::HandleObject obj, - js::Shape *shape, unsigned attrs, unsigned mask, - JSPropertyOp getter, JSStrictPropertyOp setter); + static js::UnrootedShape changeProperty(JSContext *cx, js::HandleObject obj, + js::RawShape shape, unsigned attrs, unsigned mask, + JSPropertyOp getter, JSStrictPropertyOp setter); static inline bool changePropertyAttributes(JSContext *cx, js::HandleObject obj, js::Shape *shape, unsigned attrs); @@ -1176,14 +1182,14 @@ js_CreateThis(JSContext *cx, js::Class *clasp, js::HandleObject callee); * Find or create a property named by id in obj's scope, with the given getter * and setter, slot, attributes, and other members. */ -extern js::Shape * -js_AddNativeProperty(JSContext *cx, js::HandleObject obj, jsid id, +extern js::UnrootedShape +js_AddNativeProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JSPropertyOp getter, JSStrictPropertyOp setter, uint32_t slot, unsigned attrs, unsigned flags, int shortid); extern JSBool -js_DefineOwnProperty(JSContext *cx, js::HandleObject obj, js::HandleId id, - const js::Value &descriptor, JSBool *bp); +js_DefineOwnProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, + const JS::Value &descriptor, JSBool *bp); namespace js { @@ -1203,12 +1209,12 @@ const unsigned DNP_SKIP_TYPE = 8; /* Don't update type information */ /* * Return successfully added or changed shape or NULL on error. */ -extern Shape * +extern bool DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue value, PropertyOp getter, StrictPropertyOp setter, unsigned attrs, unsigned flags, int shortid, unsigned defineHow = 0); -inline Shape * +inline bool DefineNativeProperty(JSContext *cx, HandleObject obj, PropertyName *name, HandleValue value, PropertyOp getter, StrictPropertyOp setter, unsigned attrs, unsigned flags, int shortid, unsigned defineHow = 0) @@ -1292,7 +1298,7 @@ const unsigned JSGET_CACHE_RESULT = 1; // from a caching interpreter opcode */ extern JSBool js_NativeGet(JSContext *cx, js::Handle obj, js::Handle pobj, - js::Shape *shape, unsigned getHow, js::Value *vp); + js::Handle shape, unsigned getHow, js::MutableHandle vp); extern JSBool js_NativeSet(JSContext *cx, js::Handle obj, js::Handle receiver, diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 347de61f8a5..2f00c187b39 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -272,7 +272,7 @@ JSObject::dynamicSlotIndex(size_t slot) } inline void -JSObject::setLastPropertyInfallible(js::Shape *shape) +JSObject::setLastPropertyInfallible(js::UnrootedShape shape) { JS_ASSERT(!shape->inDictionary()); JS_ASSERT(shape->compartment() == compartment()); @@ -288,7 +288,8 @@ JSObject::removeLastProperty(JSContext *cx) { JS_ASSERT(canRemoveLastProperty()); js::RootedObject self(cx, this); - JS_ALWAYS_TRUE(setLastProperty(cx, self, lastProperty()->previous())); + js::RootedShape prev(cx, lastProperty()->previous()); + JS_ALWAYS_TRUE(setLastProperty(cx, self, prev)); } inline bool @@ -302,7 +303,7 @@ JSObject::canRemoveLastProperty() * converted to dictionary mode instead. See BaseShape comment in jsscope.h */ JS_ASSERT(!inDictionaryMode()); - js::Shape *previous = lastProperty()->previous(); + js::UnrootedShape previous = lastProperty()->previous().get(); return previous->getObjectParent() == lastProperty()->getObjectParent() && previous->getObjectFlags() == lastProperty()->getObjectFlags(); } @@ -1522,7 +1523,8 @@ CopyInitializerObject(JSContext *cx, HandleObject baseobj) if (!obj) return NULL; - if (!JSObject::setLastProperty(cx, obj, baseobj->lastProperty())) + RootedShape lastProp(cx, baseobj->lastProperty()); + if (!JSObject::setLastProperty(cx, obj, lastProp)) return NULL; return obj; @@ -1558,7 +1560,7 @@ GuessArrayGCKind(size_t numSlots) * may or may not need dynamic slots. */ inline bool -PreallocateObjectDynamicSlots(JSContext *cx, Shape *shape, HeapSlot **slots) +PreallocateObjectDynamicSlots(JSContext *cx, UnrootedShape shape, HeapSlot **slots) { if (size_t count = JSObject::dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan())) { *slots = cx->pod_malloc(count); @@ -1673,10 +1675,10 @@ js_InitClass(JSContext *cx, js::HandleObject obj, JSObject *parent_proto, * (i.e., obj has ever been on a prototype or parent chain). */ extern bool -js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id); +js_PurgeScopeChainHelper(JSContext *cx, JS::HandleObject obj, JS::HandleId id); inline bool -js_PurgeScopeChain(JSContext *cx, JSObject *obj, jsid id) +js_PurgeScopeChain(JSContext *cx, JS::HandleObject obj, JS::HandleId id) { if (obj->isDelegate()) return js_PurgeScopeChainHelper(cx, obj, id); diff --git a/js/src/jspropertycacheinlines.h b/js/src/jspropertycacheinlines.h index fafe7360814..c95616126c2 100644 --- a/js/src/jspropertycacheinlines.h +++ b/js/src/jspropertycacheinlines.h @@ -35,7 +35,7 @@ js::PropertyCache::test(JSContext *cx, jsbytecode *pc, JSObject *&obj, JS_ASSERT(this == &cx->propertyCache()); - Shape *kshape = obj->lastProperty(); + UnrootedShape kshape = obj->lastProperty(); entry = &table[hash(pc, kshape)]; PCMETER(pctestentry = entry); PCMETER(tests++); @@ -64,9 +64,11 @@ JS_ALWAYS_INLINE bool js::PropertyCache::testForSet(JSContext *cx, jsbytecode *pc, JSObject *obj, PropertyCacheEntry **entryp, JSObject **obj2p, PropertyName **namep) { + AutoAssertNoGC nogc; + JS_ASSERT(this == &cx->propertyCache()); - Shape *kshape = obj->lastProperty(); + UnrootedShape kshape = obj->lastProperty(); PropertyCacheEntry *entry = &table[hash(pc, kshape)]; *entryp = entry; PCMETER(pctestentry = entry); diff --git a/js/src/jspropertytree.cpp b/js/src/jspropertytree.cpp index 29c4d758a84..2d3217dbf2f 100644 --- a/js/src/jspropertytree.cpp +++ b/js/src/jspropertytree.cpp @@ -30,19 +30,17 @@ ShapeHasher::match(const Key k, const Lookup &l) return k->matches(l); } -Shape * +UnrootedShape PropertyTree::newShape(JSContext *cx) { - Shape *shape = js_NewGCShape(cx); - if (!shape) { + UnrootedShape shape = js_NewGCShape(cx); + if (!shape) JS_ReportOutOfMemory(cx); - return NULL; - } return shape; } static KidsHash * -HashChildren(Shape *kid1, Shape *kid2) +HashChildren(UnrootedShape kid1, UnrootedShape kid2) { KidsHash *hash = js_new(); if (!hash || !hash->init(2)) { @@ -56,7 +54,7 @@ HashChildren(Shape *kid1, Shape *kid2) } bool -PropertyTree::insertChild(JSContext *cx, Shape *parent, Shape *child) +PropertyTree::insertChild(JSContext *cx, UnrootedShape parent, UnrootedShape child) { JS_ASSERT(!parent->inDictionary()); JS_ASSERT(!child->parent); @@ -73,7 +71,7 @@ PropertyTree::insertChild(JSContext *cx, Shape *parent, Shape *child) } if (kidp->isShape()) { - Shape *shape = kidp->toShape(); + UnrootedShape shape = kidp->toShape(); JS_ASSERT(shape != child); JS_ASSERT(!shape->matches(child)); @@ -97,7 +95,7 @@ PropertyTree::insertChild(JSContext *cx, Shape *parent, Shape *child) } void -Shape::removeChild(Shape *child) +Shape::removeChild(UnrootedShape child) { JS_ASSERT(!child->inDictionary()); JS_ASSERT(child->parent == this); @@ -127,74 +125,76 @@ Shape::removeChild(Shape *child) } } -Shape * +UnrootedShape PropertyTree::getChild(JSContext *cx, Shape *parent_, uint32_t nfixed, const StackShape &child) { AssertCanGC(); - Shape *shape = NULL; + { + UnrootedShape shape = NULL; - JS_ASSERT(parent_); + JS_ASSERT(parent_); - /* - * The property tree has extremely low fan-out below its root in - * popular embeddings with real-world workloads. Patterns such as - * defining closures that capture a constructor's environment as - * getters or setters on the new object that is passed in as - * |this| can significantly increase fan-out below the property - * tree root -- see bug 335700 for details. - */ - KidsPointer *kidp = &parent_->kids; - if (kidp->isShape()) { - Shape *kid = kidp->toShape(); - if (kid->matches(child)) - shape = kid; - } else if (kidp->isHash()) { - if (KidsHash::Ptr p = kidp->toHash()->lookup(child)) - shape = *p; - } else { - /* If kidp->isNull(), we always insert. */ - } + /* + * The property tree has extremely low fan-out below its root in + * popular embeddings with real-world workloads. Patterns such as + * defining closures that capture a constructor's environment as + * getters or setters on the new object that is passed in as + * |this| can significantly increase fan-out below the property + * tree root -- see bug 335700 for details. + */ + KidsPointer *kidp = &parent_->kids; + if (kidp->isShape()) { + UnrootedShape kid = kidp->toShape(); + if (kid->matches(child)) + shape = kid; + } else if (kidp->isHash()) { + if (KidsHash::Ptr p = kidp->toHash()->lookup(child)) + shape = *p; + } else { + /* If kidp->isNull(), we always insert. */ + } #ifdef JSGC_INCREMENTAL - if (shape) { - JSCompartment *comp = shape->compartment(); - if (comp->needsBarrier()) { - /* - * We need a read barrier for the shape tree, since these are weak - * pointers. - */ - Shape *tmp = shape; - MarkShapeUnbarriered(comp->barrierTracer(), &tmp, "read barrier"); - JS_ASSERT(tmp == shape); - } else if (comp->isGCSweeping() && !shape->isMarked() && - !shape->arenaHeader()->allocatedDuringIncremental) - { - /* - * The shape we've found is unreachable and due to be finalized, so - * remove our weak reference to it and don't use it. - */ - JS_ASSERT(parent_->isMarked()); - parent_->removeChild(shape); - shape = NULL; + if (shape) { + JSCompartment *comp = shape->compartment(); + if (comp->needsBarrier()) { + /* + * We need a read barrier for the shape tree, since these are weak + * pointers. + */ + Shape *tmp = shape; + MarkShapeUnbarriered(comp->barrierTracer(), &tmp, "read barrier"); + JS_ASSERT(tmp == shape); + } else if (comp->isGCSweeping() && !shape->isMarked() && + !shape->arenaHeader()->allocatedDuringIncremental) + { + /* + * The shape we've found is unreachable and due to be finalized, so + * remove our weak reference to it and don't use it. + */ + JS_ASSERT(parent_->isMarked()); + parent_->removeChild(shape); + shape = NULL; + } } - } #endif - if (shape) - return shape; + if (shape) + return shape; + } StackShape::AutoRooter childRoot(cx, &child); RootedShape parent(cx, parent_); - shape = newShape(cx); + UnrootedShape shape = newShape(cx); if (!shape) - return NULL; + return UnrootedShape(NULL); new (shape) Shape(child, nfixed); if (!insertChild(cx, parent, shape)) - return NULL; + return UnrootedShape(NULL); return shape; } @@ -236,7 +236,7 @@ Shape::finalize(FreeOp *fop) #ifdef DEBUG void -KidsPointer::checkConsistency(Shape *aKid) const +KidsPointer::checkConsistency(UnrootedShape aKid) const { if (isShape()) { JS_ASSERT(toShape() == aKid); @@ -323,13 +323,13 @@ Shape::dumpSubtree(JSContext *cx, int level, FILE *fp) const if (!kids.isNull()) { ++level; if (kids.isShape()) { - Shape *kid = kids.toShape(); + UnrootedShape kid = kids.toShape(); JS_ASSERT(kid->parent == this); kid->dumpSubtree(cx, level, fp); } else { const KidsHash &hash = *kids.toHash(); for (KidsHash::Range range = hash.all(); !range.empty(); range.popFront()) { - Shape *kid = range.front(); + RawShape kid = range.front(); JS_ASSERT(kid->parent == this); kid->dumpSubtree(cx, level, fp); @@ -363,7 +363,7 @@ js::PropertyTree::dumpShapes(JSRuntime *rt) typedef JSCompartment::EmptyShapeSet HS; HS &h = c->emptyShapes; for (HS::Range r = h.all(); !r.empty(); r.popFront()) { - Shape *empty = r.front(); + RawShape empty = r.front(); empty->dumpSubtree(rt, 0, dumpfp); putc('\n', dumpfp); } diff --git a/js/src/jspropertytree.h b/js/src/jspropertytree.h index fa406f702e4..a538b935b47 100644 --- a/js/src/jspropertytree.h +++ b/js/src/jspropertytree.h @@ -7,21 +7,22 @@ #ifndef jspropertytree_h___ #define jspropertytree_h___ -#include "jsprvtd.h" - #include "js/HashTable.h" namespace js { +ForwardDeclare(Shape); +struct StackShape; + struct ShapeHasher { - typedef js::Shape *Key; - typedef js::StackShape Lookup; + typedef RawShape Key; + typedef StackShape Lookup; static inline HashNumber hash(const Lookup &l); static inline bool match(Key k, const Lookup &l); }; -typedef HashSet KidsHash; +typedef HashSet KidsHash; class KidsPointer { private: @@ -38,14 +39,14 @@ class KidsPointer { void setNull() { w = 0; } bool isShape() const { return (w & TAG) == SHAPE && !isNull(); } - js::Shape *toShape() const { + UnrootedShape toShape() const { JS_ASSERT(isShape()); - return reinterpret_cast(w & ~uintptr_t(TAG)); + return reinterpret_cast(w & ~uintptr_t(TAG)); } - void setShape(js::Shape *shape) { + void setShape(UnrootedShape shape) { JS_ASSERT(shape); - JS_ASSERT((reinterpret_cast(shape) & TAG) == 0); - w = reinterpret_cast(shape) | SHAPE; + JS_ASSERT((reinterpret_cast(static_cast(shape)) & TAG) == 0); + w = reinterpret_cast(static_cast(shape)) | SHAPE; } bool isHash() const { return (w & TAG) == HASH; } @@ -60,7 +61,7 @@ class KidsPointer { } #ifdef DEBUG - void checkConsistency(js::Shape *aKid) const; + void checkConsistency(UnrootedShape aKid) const; #endif }; @@ -70,7 +71,7 @@ class PropertyTree JSCompartment *compartment; - bool insertChild(JSContext *cx, js::Shape *parent, js::Shape *child); + bool insertChild(JSContext *cx, UnrootedShape parent, UnrootedShape child); PropertyTree(); @@ -82,12 +83,11 @@ class PropertyTree { } - js::Shape *newShape(JSContext *cx); - js::Shape *getChild(JSContext *cx, Shape *parent, uint32_t nfixed, const StackShape &child); + UnrootedShape newShape(JSContext *cx); + UnrootedShape getChild(JSContext *cx, Shape *parent, uint32_t nfixed, const StackShape &child); #ifdef DEBUG static void dumpShapes(JSRuntime *rt); - static void meter(JSBasicStats *bs, js::Shape *node); #endif }; diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index d399b3fd931..01703d554b5 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -142,15 +142,7 @@ class InlineMap; class LifoAlloc; -class BaseShape; -class UnownedBaseShape; struct Shape; -struct EmptyShape; -class ShapeKindArray; -class Bindings; - -struct StackBaseShape; -struct StackShape; class Breakpoint; class BreakpointSite; @@ -207,7 +199,6 @@ struct TypeCompartment; } /* namespace types */ typedef JS::Handle HandleShape; -typedef JS::Handle HandleBaseShape; typedef JS::Handle HandleTypeObject; typedef JS::Handle HandleAtom; typedef JS::Handle HandlePropertyName; @@ -218,7 +209,6 @@ typedef JS::MutableHandle MutableHandleAtom; typedef JSAtom * RawAtom; typedef js::Rooted RootedShape; -typedef js::Rooted RootedBaseShape; typedef js::Rooted RootedTypeObject; typedef js::Rooted RootedAtom; typedef js::Rooted RootedPropertyName; diff --git a/js/src/jsscope.cpp b/js/src/jsscope.cpp index 383a956004d..1c009cc2852 100644 --- a/js/src/jsscope.cpp +++ b/js/src/jsscope.cpp @@ -37,7 +37,7 @@ using namespace js::gc; using mozilla::DebugOnly; bool -ShapeTable::init(JSRuntime *rt, Shape *lastProp) +ShapeTable::init(JSRuntime *rt, UnrootedShape lastProp) { /* * Either we're creating a table for a large scope that was populated @@ -92,7 +92,7 @@ Shape::makeOwnBaseShape(JSContext *cx, HandleShape shape) } void -Shape::handoffTableTo(Shape *shape) +Shape::handoffTableTo(UnrootedShape shape) { AutoAssertNoGC nogc; JS_ASSERT(inDictionary() && shape->inDictionary()); @@ -273,7 +273,7 @@ ShapeTable::grow(JSContext *cx) return true; } -Shape * +UnrootedShape Shape::getChildBinding(JSContext *cx, const StackShape &child) { AssertCanGC(); @@ -287,12 +287,10 @@ Shape::getChildBinding(JSContext *cx, const StackShape &child) return cx->propertyTree().getChild(cx, this, nfixed, child); } -/* static */ Shape * +/* static */ UnrootedShape Shape::replaceLastProperty(JSContext *cx, const StackBaseShape &base, - TaggedProto proto, Shape *shape_) + TaggedProto proto, HandleShape shape) { - RootedShape shape(cx, shape_); - JS_ASSERT(!shape->inDictionary()); if (!shape->parent) { @@ -307,7 +305,7 @@ Shape::replaceLastProperty(JSContext *cx, const StackBaseShape &base, { UnrootedUnownedBaseShape nbase = BaseShape::getUnowned(cx, base); if (!nbase) - return NULL; + return UnrootedShape(NULL); child.base = nbase; } @@ -320,8 +318,8 @@ Shape::replaceLastProperty(JSContext *cx, const StackBaseShape &base, * which must be lastProperty() if inDictionaryMode(), else parent must be * one of lastProperty() or lastProperty()->parent. */ -Shape * -JSObject::getChildProperty(JSContext *cx, Shape *parent, StackShape &child) +/* static */ UnrootedShape +JSObject::getChildProperty(JSContext *cx, HandleObject obj, HandleShape parent, StackShape &child) { /* * Shared properties have no slot, but slot_ will reflect that of parent. @@ -333,40 +331,38 @@ JSObject::getChildProperty(JSContext *cx, Shape *parent, StackShape &child) } else { if (child.hasMissingSlot()) { uint32_t slot; - if (!allocSlot(cx, &slot)) - return NULL; + if (!allocSlot(cx, obj, &slot)) + return UnrootedShape(NULL); child.setSlot(slot); } else { /* Slots can only be allocated out of order on objects in dictionary mode. */ - JS_ASSERT(inDictionaryMode() || + JS_ASSERT(obj->inDictionaryMode() || parent->hasMissingSlot() || child.slot() == parent->maybeSlot() + 1); } } - Shape *shape; + RootedShape shape(cx); - RootedObject self(cx, this); - - if (inDictionaryMode()) { - JS_ASSERT(parent == lastProperty()); + if (obj->inDictionaryMode()) { + JS_ASSERT(parent == obj->lastProperty()); StackShape::AutoRooter childRoot(cx, &child); shape = js_NewGCShape(cx); if (!shape) - return NULL; - if (child.hasSlot() && child.slot() >= self->lastProperty()->base()->slotSpan()) { - if (!JSObject::setSlotSpan(cx, self, child.slot() + 1)) - return NULL; + return UnrootedShape(NULL); + if (child.hasSlot() && child.slot() >= obj->lastProperty()->base()->slotSpan()) { + if (!JSObject::setSlotSpan(cx, obj, child.slot() + 1)) + return UnrootedShape(NULL); } - shape->initDictionaryShape(child, self->numFixedSlots(), &self->shape_); + shape->initDictionaryShape(child, obj->numFixedSlots(), &obj->shape_); } else { - shape = cx->propertyTree().getChild(cx, parent, self->numFixedSlots(), child); + shape = cx->propertyTree().getChild(cx, parent, obj->numFixedSlots(), child); if (!shape) - return NULL; + return UnrootedShape(NULL); //JS_ASSERT(shape->parent == parent); //JS_ASSERT_IF(parent != lastProperty(), parent == lastProperty()->parent); - if (!JSObject::setLastProperty(cx, self, shape)) - return NULL; + if (!JSObject::setLastProperty(cx, obj, shape)) + return UnrootedShape(NULL); } return shape; @@ -397,7 +393,7 @@ JSObject::toDictionaryMode(JSContext *cx) while (shape) { JS_ASSERT(!shape->inDictionary()); - Shape *dprop = js_NewGCShape(cx); + UnrootedShape dprop = js_NewGCShape(cx); if (!dprop) { js_ReportOutOfMemory(cx); return false; @@ -452,65 +448,60 @@ NormalizeGetterAndSetter(JSObject *obj, return true; } -Shape * -JSObject::addProperty(JSContext *cx, jsid id, +/* static */ UnrootedShape +JSObject::addProperty(JSContext *cx, HandleObject obj, HandleId id, PropertyOp getter, StrictPropertyOp setter, uint32_t slot, unsigned attrs, unsigned flags, int shortid, bool allowDictionary) { JS_ASSERT(!JSID_IS_VOID(id)); - if (!isExtensible()) { - reportNotExtensible(cx); - return NULL; + if (!obj->isExtensible()) { + obj->reportNotExtensible(cx); + return UnrootedShape(NULL); } - NormalizeGetterAndSetter(this, id, attrs, flags, getter, setter); - - RootedObject self(cx, this); + NormalizeGetterAndSetter(obj, id, attrs, flags, getter, setter); Shape **spp = NULL; - if (inDictionaryMode()) - spp = lastProperty()->table().search(id, true); + if (obj->inDictionaryMode()) + spp = obj->lastProperty()->table().search(id, true); - return self->addPropertyInternal(cx, id, getter, setter, slot, attrs, flags, shortid, - spp, allowDictionary); + return addPropertyInternal(cx, obj, id, getter, setter, slot, attrs, flags, shortid, + spp, allowDictionary); } -Shape * -JSObject::addPropertyInternal(JSContext *cx, jsid id_, +/* static */ UnrootedShape +JSObject::addPropertyInternal(JSContext *cx, HandleObject obj, HandleId id, PropertyOp getter, StrictPropertyOp setter, uint32_t slot, unsigned attrs, unsigned flags, int shortid, Shape **spp, bool allowDictionary) { AssertCanGC(); - JS_ASSERT_IF(!allowDictionary, !inDictionaryMode()); - - RootedId id(cx, id_); - RootedObject self(cx, this); + JS_ASSERT_IF(!allowDictionary, !obj->inDictionaryMode()); AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); ShapeTable *table = NULL; - if (!inDictionaryMode()) { + if (!obj->inDictionaryMode()) { bool stableSlot = (slot == SHAPE_INVALID_SLOT) || - lastProperty()->hasMissingSlot() || - (slot == lastProperty()->maybeSlot() + 1); + obj->lastProperty()->hasMissingSlot() || + (slot == obj->lastProperty()->maybeSlot() + 1); JS_ASSERT_IF(!allowDictionary, stableSlot); if (allowDictionary && - (!stableSlot || lastProperty()->entryCount() >= PropertyTree::MAX_HEIGHT)) { - if (!toDictionaryMode(cx)) - return NULL; - table = &self->lastProperty()->table(); + (!stableSlot || obj->lastProperty()->entryCount() >= PropertyTree::MAX_HEIGHT)) { + if (!obj->toDictionaryMode(cx)) + return UnrootedShape(NULL); + table = &obj->lastProperty()->table(); spp = table->search(id, true); } } else { - table = &lastProperty()->table(); + table = &obj->lastProperty()->table(); if (table->needsToGrow()) { if (!table->grow(cx)) - return NULL; + return UnrootedShape(NULL); spp = table->search(id, true); JS_ASSERT(!SHAPE_FETCH(spp)); } @@ -519,37 +510,36 @@ JSObject::addPropertyInternal(JSContext *cx, jsid id_, JS_ASSERT(!!table == !!spp); /* Find or create a property tree node labeled by our arguments. */ - Shape *shape; + UnrootedShape shape; { - shape = self->lastProperty(); + RootedShape last(cx, obj->lastProperty()); uint32_t index; bool indexed = js_IdIsIndex(id, &index); UnrootedUnownedBaseShape nbase; - if (shape->base()->matchesGetterSetter(getter, setter) && !indexed) { - nbase = shape->base()->unowned(); + if (last->base()->matchesGetterSetter(getter, setter) && !indexed) { + nbase = last->base()->unowned(); } else { - StackBaseShape base(shape->base()); + StackBaseShape base(last->base()); base.updateGetterSetter(attrs, getter, setter); if (indexed) base.flags |= BaseShape::INDEXED; nbase = BaseShape::getUnowned(cx, base); if (!nbase) - return NULL; + return UnrootedShape(NULL); } - StackShape child(nbase, id, slot, self->numFixedSlots(), attrs, flags, shortid); - DropUnrooted(nbase); - shape = self->getChildProperty(cx, self->lastProperty(), child); + StackShape child(DropUnrooted(nbase), id, slot, obj->numFixedSlots(), attrs, flags, shortid); + shape = getChildProperty(cx, obj, last, child); } if (shape) { - JS_ASSERT(shape == self->lastProperty()); + JS_ASSERT(shape == obj->lastProperty()); if (table) { /* Store the tree node pointer in the table entry for id. */ - SHAPE_STORE_PRESERVING_COLLISION(spp, shape); + SHAPE_STORE_PRESERVING_COLLISION(spp, static_cast(shape)); ++table->entryCount; /* Pass the table along to the new last property, namely shape. */ @@ -557,12 +547,12 @@ JSObject::addPropertyInternal(JSContext *cx, jsid id_, shape->parent->handoffTableTo(shape); } - self->checkShapeConsistency(); + obj->checkShapeConsistency(); return shape; } - self->checkShapeConsistency(); - return NULL; + obj->checkShapeConsistency(); + return UnrootedShape(NULL); } /* @@ -589,41 +579,39 @@ CheckCanChangeAttrs(JSContext *cx, JSObject *obj, Shape *shape, unsigned *attrsp return true; } -Shape * -JSObject::putProperty(JSContext *cx, jsid id_, +/* static */ UnrootedShape +JSObject::putProperty(JSContext *cx, HandleObject obj, HandleId id, PropertyOp getter, StrictPropertyOp setter, uint32_t slot, unsigned attrs, unsigned flags, int shortid) { - RootedId id(cx, id_); JS_ASSERT(!JSID_IS_VOID(id)); - NormalizeGetterAndSetter(this, id, attrs, flags, getter, setter); + NormalizeGetterAndSetter(obj, id, attrs, flags, getter, setter); - RootedObject self(cx, this); AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); /* Search for id in order to claim its entry if table has been allocated. */ Shape **spp; - RootedShape shape(cx, Shape::search(cx, lastProperty(), id, &spp, true)); + RootedShape shape(cx, Shape::search(cx, obj->lastProperty(), id, &spp, true)); if (!shape) { /* * You can't add properties to a non-extensible object, but you can change * attributes of properties in such objects. */ - if (!self->isExtensible()) { - self->reportNotExtensible(cx); - return NULL; + if (!obj->isExtensible()) { + obj->reportNotExtensible(cx); + return UnrootedShape(NULL); } - return self->addPropertyInternal(cx, id, getter, setter, slot, attrs, flags, shortid, spp, true); + return addPropertyInternal(cx, obj, id, getter, setter, slot, attrs, flags, shortid, spp, true); } /* Property exists: search must have returned a valid *spp. */ JS_ASSERT_IF(spp, !SHAPE_IS_REMOVED(*spp)); - if (!CheckCanChangeAttrs(cx, self, shape, &attrs)) - return NULL; + if (!CheckCanChangeAttrs(cx, obj, shape, &attrs)) + return UnrootedShape(NULL); /* * If the caller wants to allocate a slot, but doesn't care which slot, @@ -639,13 +627,13 @@ JSObject::putProperty(JSContext *cx, jsid id_, { uint32_t index; bool indexed = js_IdIsIndex(id, &index); - StackBaseShape base(self->lastProperty()->base()); + StackBaseShape base(obj->lastProperty()->base()); base.updateGetterSetter(attrs, getter, setter); if (indexed) base.flags |= BaseShape::INDEXED; nbase = BaseShape::getUnowned(cx, base); if (!nbase) - return NULL; + return UnrootedShape(NULL); } /* @@ -660,33 +648,33 @@ JSObject::putProperty(JSContext *cx, jsid id_, * The shape tree is shared immutable, and we can't removeProperty and then * addPropertyInternal because a failure under add would lose data. */ - if (shape != self->lastProperty() && !self->inDictionaryMode()) { - if (!self->toDictionaryMode(cx)) - return NULL; - spp = self->lastProperty()->table().search(shape->propid(), false); + if (shape != obj->lastProperty() && !obj->inDictionaryMode()) { + if (!obj->toDictionaryMode(cx)) + return UnrootedShape(NULL); + spp = obj->lastProperty()->table().search(shape->propid(), false); shape = SHAPE_FETCH(spp); } JS_ASSERT_IF(shape->hasSlot() && !(attrs & JSPROP_SHARED), shape->slot() == slot); - if (self->inDictionaryMode()) { + if (obj->inDictionaryMode()) { /* * Updating some property in a dictionary-mode object. Create a new * shape for the existing property, and also generate a new shape for * the last property of the dictionary (unless the modified property * is also the last property). */ - bool updateLast = (shape == self->lastProperty()); - shape = self->replaceWithNewEquivalentShape(cx, shape); + bool updateLast = (shape == obj->lastProperty()); + shape = obj->replaceWithNewEquivalentShape(cx, shape); if (!shape) - return NULL; - if (!updateLast && !self->generateOwnShape(cx)) - return NULL; + return UnrootedShape(NULL); + if (!updateLast && !obj->generateOwnShape(cx)) + return UnrootedShape(NULL); /* FIXME bug 593129 -- slot allocation and JSObject *this must move out of here! */ if (slot == SHAPE_INVALID_SLOT && !(attrs & JSPROP_SHARED)) { - if (!self->allocSlot(cx, &slot)) - return NULL; + if (!allocSlot(cx, obj, &slot)) + return UnrootedShape(NULL); } if (updateLast) @@ -703,23 +691,24 @@ JSObject::putProperty(JSContext *cx, jsid id_, * Updating the last property in a non-dictionary-mode object. Find an * alternate shared child of the last property's previous shape. */ - StackBaseShape base(self->lastProperty()->base()); + StackBaseShape base(obj->lastProperty()->base()); base.updateGetterSetter(attrs, getter, setter); UnrootedUnownedBaseShape nbase = BaseShape::getUnowned(cx, base); if (!nbase) - return NULL; + return UnrootedShape(NULL); - JS_ASSERT(shape == self->lastProperty()); + JS_ASSERT(shape == obj->lastProperty()); /* Find or create a property tree node labeled by our arguments. */ - StackShape child(nbase, id, slot, self->numFixedSlots(), attrs, flags, shortid); + StackShape child(nbase, id, slot, obj->numFixedSlots(), attrs, flags, shortid); DropUnrooted(nbase); - Shape *newShape = self->getChildProperty(cx, shape->parent, child); + RootedShape parent(cx, shape->parent); + UnrootedShape newShape = JSObject::getChildProperty(cx, obj, parent, child); if (!newShape) { - self->checkShapeConsistency(); - return NULL; + obj->checkShapeConsistency(); + return UnrootedShape(NULL); } shape = newShape; @@ -732,18 +721,18 @@ JSObject::putProperty(JSContext *cx, jsid id_, * property (shape here) has a slotSpan that does not cover it. */ if (hadSlot && !shape->hasSlot()) { - if (oldSlot < self->slotSpan()) - self->freeSlot(oldSlot); + if (oldSlot < obj->slotSpan()) + obj->freeSlot(oldSlot); ++cx->runtime->propertyRemovals; } - self->checkShapeConsistency(); + obj->checkShapeConsistency(); return shape; } -/* static */ Shape * -JSObject::changeProperty(JSContext *cx, HandleObject obj, Shape *shape, unsigned attrs, unsigned mask, +/* static */ UnrootedShape +JSObject::changeProperty(JSContext *cx, HandleObject obj, RawShape shape, unsigned attrs, unsigned mask, PropertyOp getter, StrictPropertyOp setter) { JS_ASSERT(obj->nativeContainsNoAllocation(*shape)); @@ -764,7 +753,7 @@ JSObject::changeProperty(JSContext *cx, HandleObject obj, Shape *shape, unsigned setter = NULL; if (!CheckCanChangeAttrs(cx, obj, shape, &attrs)) - return NULL; + return UnrootedShape(NULL); if (shape->attrs == attrs && shape->getter() == getter && shape->setter() == setter) return shape; @@ -775,8 +764,9 @@ JSObject::changeProperty(JSContext *cx, HandleObject obj, Shape *shape, unsigned * removeProperty because it will free an allocated shape->slot, and * putProperty won't re-allocate it. */ - Shape *newShape = obj->putProperty(cx, shape->propid(), getter, setter, shape->maybeSlot(), - attrs, shape->flags, shape->maybeShortid()); + RootedId propid(cx, shape->propid()); + UnrootedShape newShape = putProperty(cx, obj, propid, getter, setter, shape->maybeSlot(), + attrs, shape->flags, shape->maybeShortid()); obj->checkShapeConsistency(); return newShape; @@ -862,18 +852,20 @@ JSObject::removeProperty(JSContext *cx, jsid id_) * checks not to alter significantly the complexity of the * delete in debug builds, see bug 534493. */ - Shape *aprop = self->lastProperty(); + UnrootedShape aprop = self->lastProperty(); for (int n = 50; --n >= 0 && aprop->parent; aprop = aprop->parent) JS_ASSERT_IF(aprop != shape, self->nativeContainsNoAllocation(*aprop)); #endif } - /* Remove shape from its non-circular doubly linked list. */ - Shape *oldLastProp = self->lastProperty(); - shape->removeFromDictionary(self); + { + /* Remove shape from its non-circular doubly linked list. */ + UnrootedShape oldLastProp = self->lastProperty(); + shape->removeFromDictionary(self); - /* Hand off table from the old to new last property. */ - oldLastProp->handoffTableTo(self->lastProperty()); + /* Hand off table from the old to new last property. */ + oldLastProp->handoffTableTo(self->lastProperty()); + } /* Generate a new shape for the object, infallibly. */ JS_ALWAYS_TRUE(self->generateOwnShape(cx, spare)); @@ -900,7 +892,7 @@ JSObject::removeProperty(JSContext *cx, jsid id_) /* static */ void JSObject::clear(JSContext *cx, HandleObject obj) { - Shape *shape = obj->lastProperty(); + RootedShape shape(cx, obj->lastProperty()); JS_ASSERT(obj->inDictionaryMode() == shape->inDictionary()); while (shape->parent) { @@ -936,6 +928,7 @@ JSObject::rollbackProperties(JSContext *cx, uint32_t slotSpan) Shape * JSObject::replaceWithNewEquivalentShape(JSContext *cx, Shape *oldShape, Shape *newShape) { + AssertCanGC(); JS_ASSERT(cx->compartment == oldShape->compartment()); JS_ASSERT_IF(oldShape != lastProperty(), inDictionaryMode() && @@ -1016,7 +1009,7 @@ JSObject::setParent(JSContext *cx, HandleObject obj, HandleObject parent) return true; } - Shape *newShape = Shape::setObjectParent(cx, parent, obj->getTaggedProto(), obj->shape_); + UnrootedShape newShape = Shape::setObjectParent(cx, parent, obj->getTaggedProto(), obj->shape_); if (!newShape) return false; @@ -1024,7 +1017,7 @@ JSObject::setParent(JSContext *cx, HandleObject obj, HandleObject parent) return true; } -/* static */ Shape * +/* static */ UnrootedShape Shape::setObjectParent(JSContext *cx, JSObject *parent, TaggedProto proto, Shape *last) { if (last->getObjectParent() == parent) @@ -1033,7 +1026,8 @@ Shape::setObjectParent(JSContext *cx, JSObject *parent, TaggedProto proto, Shape StackBaseShape base(last); base.parent = parent; - return replaceLastProperty(cx, base, proto, last); + RootedShape lastRoot(cx, last); + return replaceLastProperty(cx, base, proto, lastRoot); } bool @@ -1080,7 +1074,7 @@ JSObject::setFlag(JSContext *cx, /*BaseShape::Flag*/ uint32_t flag_, GenerateSha return true; } - Shape *newShape = Shape::setObjectFlag(cx, flag, getTaggedProto(), lastProperty()); + UnrootedShape newShape = Shape::setObjectFlag(cx, flag, getTaggedProto(), lastProperty()); if (!newShape) return false; @@ -1088,7 +1082,7 @@ JSObject::setFlag(JSContext *cx, /*BaseShape::Flag*/ uint32_t flag_, GenerateSha return true; } -/* static */ Shape * +/* static */ UnrootedShape Shape::setObjectFlag(JSContext *cx, BaseShape::Flag flag, TaggedProto proto, Shape *last) { if (last->getObjectFlags() & flag) @@ -1097,7 +1091,8 @@ Shape::setObjectFlag(JSContext *cx, BaseShape::Flag flag, TaggedProto proto, Sha StackBaseShape base(last); base.flags |= flag; - return replaceLastProperty(cx, base, proto, last); + RootedShape lastRoot(cx, last); + return replaceLastProperty(cx, base, proto, lastRoot); } /* static */ inline HashNumber @@ -1238,7 +1233,7 @@ EmptyShape::getInitialShape(JSContext *cx, Class *clasp, TaggedProto proto, JSOb if (!nbase) return NULL; - Shape *shape = cx->propertyTree().newShape(cx); + UnrootedShape shape = cx->propertyTree().newShape(cx); if (!shape) return NULL; new (shape) EmptyShape(nbase, nfixed); @@ -1253,8 +1248,9 @@ EmptyShape::getInitialShape(JSContext *cx, Class *clasp, TaggedProto proto, JSOb } void -NewObjectCache::invalidateEntriesForShape(JSContext *cx, Shape *shape, JSObject *proto_) +NewObjectCache::invalidateEntriesForShape(JSContext *cx, HandleShape shape, HandleObject proto) { + AssertCanGC(); Class *clasp = shape->getObjectClass(); gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots()); @@ -1262,8 +1258,7 @@ NewObjectCache::invalidateEntriesForShape(JSContext *cx, Shape *shape, JSObject kind = GetBackgroundAllocKind(kind); Rooted global(cx, &shape->getObjectParent()->global()); - RootedObject proto(cx, proto_); - types::TypeObject *type = proto->getNewType(cx); + Rooted type(cx, proto->getNewType(cx)); EntryIndex entry; if (lookupGlobal(clasp, global, kind, &entry)) @@ -1275,10 +1270,11 @@ NewObjectCache::invalidateEntriesForShape(JSContext *cx, Shape *shape, JSObject } /* static */ void -EmptyShape::insertInitialShape(JSContext *cx, Shape *shape, JSObject *proto) +EmptyShape::insertInitialShape(JSContext *cx, HandleShape shape, HandleObject proto) { - InitialShapeEntry::Lookup lookup(shape->getObjectClass(), proto, shape->getObjectParent(), - shape->numFixedSlots(), shape->getObjectFlags()); + InitialShapeEntry::Lookup lookup(shape->getObjectClass(), TaggedProto(proto), + shape->getObjectParent(), shape->numFixedSlots(), + shape->getObjectFlags()); InitialShapeSet::Ptr p = cx->compartment->initialShapes.lookup(lookup); JS_ASSERT(p); @@ -1288,13 +1284,13 @@ EmptyShape::insertInitialShape(JSContext *cx, Shape *shape, JSObject *proto) /* The new shape had better be rooted at the old one. */ #ifdef DEBUG - Shape *nshape = shape; + RawShape nshape = shape; while (!nshape->isEmptyShape()) nshape = nshape->previous(); JS_ASSERT(nshape == entry.shape); #endif - entry.shape = shape; + entry.shape = shape.get(); /* * This affects the shape that will be produced by the various NewObject @@ -1315,7 +1311,7 @@ JSCompartment::sweepInitialShapeTable() if (initialShapes.initialized()) { for (InitialShapeSet::Enum e(initialShapes); !e.empty(); e.popFront()) { const InitialShapeEntry &entry = e.front(); - Shape *shape = entry.shape; + RawShape shape = entry.shape; JSObject *proto = entry.proto.raw(); if (IsShapeAboutToBeFinalized(&shape) || (entry.proto.isObject() && IsObjectAboutToBeFinalized(&proto))) { e.removeFront(); diff --git a/js/src/jsscope.h b/js/src/jsscope.h index e88ce8293da..48df01948f0 100644 --- a/js/src/jsscope.h +++ b/js/src/jsscope.h @@ -90,8 +90,12 @@ * a single BaseShape. */ +struct JSObject; + namespace js { +class Bindings; + /* Limit on the number of slotful properties in an object. */ static const uint32_t SHAPE_INVALID_SLOT = JS_BIT(24) - 1; static const uint32_t SHAPE_MAXIMUM_SLOT = JS_BIT(24) - 2; @@ -132,7 +136,7 @@ struct ShapeTable { uint32_t capacity() const { return JS_BIT(HASH_BITS - hashShift); } /* Computes the size of the entries array for a given capacity. */ - static size_t sizeOfEntries(size_t cap) { return cap * sizeof(Shape *); } + static size_t sizeOfEntries(size_t cap) { return cap * sizeof(RawShape); } /* * This counts the ShapeTable object itself (which must be @@ -160,19 +164,11 @@ struct ShapeTable { * cope or ignore. They do however use JSRuntime's calloc_ method in order * to update the malloc counter on success. */ - bool init(JSRuntime *rt, js::Shape *lastProp); + bool init(JSRuntime *rt, UnrootedShape lastProp); bool change(int log2Delta, JSContext *cx); - js::Shape **search(jsid id, bool adding); + Shape **search(jsid id, bool adding); }; -} /* namespace js */ - -struct JSObject; - -namespace js { - -class PropertyTree; - /* * Reuse the API-only JSPROP_INDEX attribute to mean shadowability. */ @@ -229,6 +225,7 @@ class PropertyTree; ForwardDeclare(UnownedBaseShape); ForwardDeclare(BaseShape); ForwardDeclare(Shape); +struct StackBaseShape; class BaseShape : public js::gc::Cell { @@ -272,13 +269,13 @@ class BaseShape : public js::gc::Cell * dictionary last properties. */ union { - js::PropertyOp rawGetter; /* getter hook for shape */ + PropertyOp rawGetter; /* getter hook for shape */ JSObject *getterObj; /* user-defined callable "get" object or null if shape->hasGetterValue() */ }; union { - js::StrictPropertyOp rawSetter; /* setter hook for shape */ + StrictPropertyOp rawSetter; /* setter hook for shape */ JSObject *setterObj; /* user-defined callable "set" object or null if shape->hasSetterValue() */ }; @@ -393,7 +390,7 @@ struct StackBaseShape PropertyOp rawGetter; StrictPropertyOp rawSetter; - StackBaseShape(UnrootedBaseShape base) + explicit StackBaseShape(UnrootedBaseShape base) : flags(base->flags & BaseShape::OBJECT_FLAG_MASK), clasp(base->clasp), parent(base->parent), @@ -409,7 +406,7 @@ struct StackBaseShape rawSetter(NULL) {} - inline StackBaseShape(Shape *shape); + inline StackBaseShape(UnrootedShape shape); inline void updateGetterSetter(uint8_t attrs, PropertyOp rawGetter, @@ -498,10 +495,10 @@ struct Shape : public js::gc::Cell last, else to obj->shape_ */ }; - static inline Shape *search(JSContext *cx, Shape *start, jsid id, - Shape ***pspp, bool adding = false); + static inline UnrootedShape search(JSContext *cx, Shape *start, jsid id, + Shape ***pspp, bool adding = false); - static inline Shape *searchNoAllocation(Shape *start, jsid id); + static inline UnrootedShape searchNoAllocation(UnrootedShape start, jsid id); inline void removeFromDictionary(JSObject *obj); inline void insertIntoDictionary(HeapPtrShape *dictp); @@ -509,16 +506,16 @@ struct Shape : public js::gc::Cell inline void initDictionaryShape(const StackShape &child, uint32_t nfixed, HeapPtrShape *dictp); - Shape *getChildBinding(JSContext *cx, const StackShape &child); + UnrootedShape getChildBinding(JSContext *cx, const StackShape &child); /* Replace the base shape of the last shape in a non-dictionary lineage with base. */ - static Shape *replaceLastProperty(JSContext *cx, const StackBaseShape &base, - TaggedProto proto, Shape *shape); + static UnrootedShape replaceLastProperty(JSContext *cx, const StackBaseShape &base, + TaggedProto proto, HandleShape shape); static bool hashify(JSContext *cx, HandleShape shape); - void handoffTableTo(Shape *newShape); + void handoffTableTo(UnrootedShape newShape); - inline void setParent(js::Shape *p); + inline void setParent(UnrootedShape p); bool ensureOwnBaseShape(JSContext *cx) { if (base()->isOwned()) @@ -531,7 +528,7 @@ struct Shape : public js::gc::Cell public: bool hasTable() const { return base()->hasTable(); } - js::ShapeTable &table() const { return base()->table(); } + ShapeTable &table() const { return base()->table(); } void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *propTableSize, size_t *kidsSize) const { @@ -553,10 +550,12 @@ struct Shape : public js::gc::Cell class Range { protected: friend struct Shape; - Shape *cursor; + + /* |cursor| is rooted manually when necessary using Range::AutoRooter. */ + RawShape cursor; public: - Range(Shape *shape) : cursor(shape) { } + Range(UnrootedShape shape) : cursor(shape) { } bool empty() const { return !cursor || cursor->isEmptyShape(); @@ -599,8 +598,8 @@ struct Shape : public js::gc::Cell Class *getObjectClass() const { return base()->clasp; } JSObject *getObjectParent() const { return base()->parent; } - static Shape *setObjectParent(JSContext *cx, JSObject *obj, TaggedProto proto, Shape *last); - static Shape *setObjectFlag(JSContext *cx, BaseShape::Flag flag, TaggedProto proto, Shape *last); + static UnrootedShape setObjectParent(JSContext *cx, JSObject *obj, TaggedProto proto, Shape *last); + static UnrootedShape setObjectFlag(JSContext *cx, BaseShape::Flag flag, TaggedProto proto, Shape *last); uint32_t getObjectFlags() const { return base()->getObjectFlags(); } bool hasObjectFlag(BaseShape::Flag flag) const { @@ -660,7 +659,7 @@ struct Shape : public js::gc::Cell // Per ES5, decode null getterObj as the undefined value, which encodes as null. Value getterValue() const { JS_ASSERT(hasGetterValue()); - return base()->getterObj ? js::ObjectValue(*base()->getterObj) : js::UndefinedValue(); + return base()->getterObj ? ObjectValue(*base()->getterObj) : UndefinedValue(); } Value getterOrUndefined() const { @@ -677,7 +676,7 @@ struct Shape : public js::gc::Cell // Per ES5, decode null setterObj as the undefined value, which encodes as null. Value setterValue() const { JS_ASSERT(hasSetterValue()); - return base()->setterObj ? js::ObjectValue(*base()->setterObj) : js::UndefinedValue(); + return base()->setterObj ? ObjectValue(*base()->setterObj) : UndefinedValue(); } Value setterOrUndefined() const { @@ -686,9 +685,9 @@ struct Shape : public js::gc::Cell : UndefinedValue(); } - void update(js::PropertyOp getter, js::StrictPropertyOp setter, uint8_t attrs); + void update(PropertyOp getter, StrictPropertyOp setter, uint8_t attrs); - inline bool matches(const Shape *other) const; + inline bool matches(const UnrootedShape other) const; inline bool matches(const StackShape &other) const; inline bool matchesParamsAfterId(UnrootedBaseShape base, uint32_t aslot, unsigned aattrs, unsigned aflags, @@ -697,7 +696,7 @@ struct Shape : public js::gc::Cell bool get(JSContext* cx, HandleObject receiver, JSObject *obj, JSObject *pobj, MutableHandleValue vp); bool set(JSContext* cx, HandleObject obj, HandleObject receiver, bool strict, MutableHandleValue vp); - BaseShape* base() const { return base_; } + RawBaseShape base() const { return base_.get(); } bool hasSlot() const { return (attrs & JSPROP_SHARED) == 0; } uint32_t slot() const { JS_ASSERT(hasSlot() && !hasMissingSlot()); return maybeSlot(); } @@ -799,18 +798,18 @@ struct Shape : public js::gc::Cell if (hasTable()) return table().entryCount; - js::Shape *shape = this; + UnrootedShape shape = this; uint32_t count = 0; - for (js::Shape::Range r = shape->all(); !r.empty(); r.popFront()) + for (Shape::Range r = shape->all(); !r.empty(); r.popFront()) ++count; return count; } bool isBigEnoughForAShapeTable() { JS_ASSERT(!hasTable()); - js::Shape *shape = this; + UnrootedShape shape = this; uint32_t count = 0; - for (js::Shape::Range r = shape->all(); !r.empty(); r.popFront()) { + for (Shape::Range r = shape->all(); !r.empty(); r.popFront()) { ++count; if (count >= ShapeTable::MIN_ENTRIES) return true; @@ -824,23 +823,23 @@ struct Shape : public js::gc::Cell #endif void finalize(FreeOp *fop); - void removeChild(js::Shape *child); + void removeChild(UnrootedShape child); - static inline void writeBarrierPre(Shape *shape); - static inline void writeBarrierPost(Shape *shape, void *addr); + static inline void writeBarrierPre(UnrootedShape shape); + static inline void writeBarrierPost(UnrootedShape shape, void *addr); /* * All weak references need a read barrier for incremental GC. This getter * method implements the read barrier. It's used to obtain initial shapes * from the compartment. */ - static inline void readBarrier(Shape *shape); + static inline void readBarrier(UnrootedShape shape); static inline ThingRootKind rootKind() { return THING_ROOT_SHAPE; } inline void markChildren(JSTracer *trc); - inline Shape *search(JSContext *cx, jsid id) { + inline UnrootedShape search(JSContext *cx, jsid id) { Shape **_; return search(cx, this, id, &_); } @@ -913,7 +912,7 @@ struct EmptyShape : public js::Shape * getInitialShape calls, until the new shape becomes unreachable in a GC * and the table entry is purged. */ - static void insertInitialShape(JSContext *cx, Shape *shape, JSObject *proto); + static void insertInitialShape(JSContext *cx, HandleShape shape, HandleObject proto); }; /* @@ -970,8 +969,8 @@ struct StackShape uint8_t flags; int16_t shortid; - StackShape(UnrootedUnownedBaseShape base, jsid propid, uint32_t slot, - uint32_t nfixed, unsigned attrs, unsigned flags, int shortid) + explicit StackShape(UnrootedUnownedBaseShape base, jsid propid, uint32_t slot, + uint32_t nfixed, unsigned attrs, unsigned flags, int shortid) : base(base), propid(propid), slot_(slot), @@ -984,9 +983,9 @@ struct StackShape JS_ASSERT(slot <= SHAPE_INVALID_SLOT); } - StackShape(const Shape *shape) + StackShape(const UnrootedShape &shape) : base(shape->base()->unowned()), - propid(const_cast(shape)->propidRef()), + propid(shape->propidRef()), slot_(shape->slotInfo & Shape::SLOT_MASK), attrs(shape->attrs), flags(shape->flags), @@ -1034,26 +1033,26 @@ struct StackShape /* js::Shape pointer tag bit indicating a collision. */ #define SHAPE_COLLISION (uintptr_t(1)) -#define SHAPE_REMOVED ((js::Shape *) SHAPE_COLLISION) +#define SHAPE_REMOVED ((RawShape) SHAPE_COLLISION) /* Macros to get and set shape pointer values and collision flags. */ #define SHAPE_IS_FREE(shape) ((shape) == NULL) #define SHAPE_IS_REMOVED(shape) ((shape) == SHAPE_REMOVED) #define SHAPE_IS_LIVE(shape) ((shape) > SHAPE_REMOVED) -#define SHAPE_FLAG_COLLISION(spp,shape) (*(spp) = (js::Shape *) \ +#define SHAPE_FLAG_COLLISION(spp,shape) (*(spp) = (RawShape) \ (uintptr_t(shape) | SHAPE_COLLISION)) #define SHAPE_HAD_COLLISION(shape) (uintptr_t(shape) & SHAPE_COLLISION) #define SHAPE_FETCH(spp) SHAPE_CLEAR_COLLISION(*(spp)) #define SHAPE_CLEAR_COLLISION(shape) \ - ((js::Shape *) (uintptr_t(shape) & ~SHAPE_COLLISION)) + ((RawShape) (uintptr_t(shape) & ~SHAPE_COLLISION)) #define SHAPE_STORE_PRESERVING_COLLISION(spp, shape) \ - (*(spp) = (js::Shape *) (uintptr_t(shape) | SHAPE_HAD_COLLISION(*(spp)))) + (*(spp) = (RawShape) (uintptr_t(shape) | SHAPE_HAD_COLLISION(*(spp)))) namespace js { -inline Shape * +inline UnrootedShape Shape::search(JSContext *cx, Shape *start, jsid id, Shape ***pspp, bool adding) { AssertCanGC(); @@ -1097,28 +1096,28 @@ Shape::search(JSContext *cx, Shape *start, jsid id, Shape ***pspp, bool adding) start->incrementNumLinearSearches(); } - for (Shape *shape = start; shape; shape = shape->parent) { + for (UnrootedShape shape = start; shape; shape = shape->parent) { if (shape->propidRef() == id) return shape; } - return NULL; + return UnrootedShape(NULL); } -/* static */ inline Shape * -Shape::searchNoAllocation(Shape *start, jsid id) +/* static */ inline UnrootedShape +Shape::searchNoAllocation(UnrootedShape start, jsid id) { if (start->hasTable()) { Shape **spp = start->table().search(id, false); return SHAPE_FETCH(spp); } - for (Shape *shape = start; shape; shape = shape->parent) { + for (UnrootedShape shape = start; shape; shape = shape->parent) { if (shape->propidRef() == id) return shape; } - return NULL; + return UnrootedShape(NULL); } void diff --git a/js/src/jsscopeinlines.h b/js/src/jsscopeinlines.h index cf84429b290..12e4b232ae0 100644 --- a/js/src/jsscopeinlines.h +++ b/js/src/jsscopeinlines.h @@ -124,7 +124,7 @@ BaseShape::matchesGetterSetter(PropertyOp rawGetter, StrictPropertyOp rawSetter) } inline -StackBaseShape::StackBaseShape(Shape *shape) +StackBaseShape::StackBaseShape(UnrootedShape shape) : flags(shape->getObjectFlags()), clasp(shape->getObjectClass()), parent(shape->getObjectParent()) @@ -238,7 +238,7 @@ StackShape::hash() const } inline bool -Shape::matches(const js::Shape *other) const +Shape::matches(const UnrootedShape other) const { return propid_.get() == other->propid_.get() && matchesParamsAfterId(other->base(), other->maybeSlot(), other->attrs, @@ -334,7 +334,7 @@ Shape::set(JSContext* cx, HandleObject obj, HandleObject receiver, bool strict, } inline void -Shape::setParent(js::Shape *p) +Shape::setParent(UnrootedShape p) { JS_ASSERT_IF(p && !p->hasMissingSlot() && !inDictionary(), p->maybeSlot() <= maybeSlot()); @@ -373,7 +373,7 @@ Shape::insertIntoDictionary(HeapPtrShape *dictp) JS_ASSERT_IF(*dictp, (*dictp)->listp == dictp); JS_ASSERT_IF(*dictp, compartment() == (*dictp)->compartment()); - setParent(*dictp); + setParent(dictp->get()); if (parent) parent->listp = &parent; listp = (HeapPtrShape *) dictp; @@ -400,7 +400,7 @@ EmptyShape::EmptyShape(UnrootedUnownedBaseShape base, uint32_t nfixed) } inline void -Shape::writeBarrierPre(Shape *shape) +Shape::writeBarrierPre(UnrootedShape shape) { #ifdef JSGC_INCREMENTAL if (!shape) @@ -408,7 +408,7 @@ Shape::writeBarrierPre(Shape *shape) JSCompartment *comp = shape->compartment(); if (comp->needsBarrier()) { - Shape *tmp = const_cast(shape); + UnrootedShape tmp = shape; MarkShapeUnbarriered(comp->barrierTracer(), &tmp, "write barrier"); JS_ASSERT(tmp == shape); } @@ -416,17 +416,17 @@ Shape::writeBarrierPre(Shape *shape) } inline void -Shape::writeBarrierPost(Shape *shape, void *addr) +Shape::writeBarrierPost(UnrootedShape shape, void *addr) { } inline void -Shape::readBarrier(Shape *shape) +Shape::readBarrier(UnrootedShape shape) { #ifdef JSGC_INCREMENTAL JSCompartment *comp = shape->compartment(); if (comp->needsBarrier()) { - Shape *tmp = const_cast(shape); + UnrootedShape tmp = shape; MarkShapeUnbarriered(comp->barrierTracer(), &tmp, "read barrier"); JS_ASSERT(tmp == shape); } diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 5a7947b8c36..822ef7fc9db 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -132,9 +132,11 @@ Bindings::initWithTemporaryStorage(JSContext *cx, InternalBindingsHandle self, StackShape child(nbase, id, slot++, 0, attrs, Shape::HAS_SHORTID, frameIndex); DropUnrooted(nbase); - self->callObjShape_ = self->callObjShape_->getChildBinding(cx, child); - if (!self->callObjShape_) + UnrootedShape shape = self->callObjShape_->getChildBinding(cx, child); + if (!shape) return false; + + self->callObjShape_ = shape; } JS_ASSERT(!bi); diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 4900f708fc7..559a04b3e6a 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -191,7 +191,7 @@ class Bindings unsigned count() const { return numArgs() + numVars(); } /* Return the initial shape of call objects created for this scope. */ - Shape *callObjShape() const { return callObjShape_; } + UnrootedShape callObjShape() const { return callObjShape_.get(); } /* Convenience method to get the var index of 'arguments'. */ static unsigned argumentsVarIndex(JSContext *cx, InternalBindingsHandle); @@ -210,7 +210,7 @@ struct RootMethods { static Bindings initial(); static ThingRootKind kind() { return THING_ROOT_BINDINGS; } static bool poisoned(const Bindings &bindings) { - return IsPoisonedPtr(bindings.callObjShape()); + return IsPoisonedPtr(static_cast(bindings.callObjShape())); } }; diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index f742424bdef..8fa92c502f6 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -3241,13 +3241,13 @@ static JSFunctionSpec string_static_methods[] = { JS_FS_END }; -Shape * +UnrootedShape StringObject::assignInitialShape(JSContext *cx) { JS_ASSERT(nativeEmpty()); - return addDataProperty(cx, NameToId(cx->names().length), - LENGTH_SLOT, JSPROP_PERMANENT | JSPROP_READONLY); + RootedId lengthid(cx, NameToId(cx->names().length)); + return addDataProperty(cx, lengthid, LENGTH_SLOT, JSPROP_PERMANENT | JSPROP_READONLY); } JSObject * diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp index c7d9ff31666..58f6c5f466b 100644 --- a/js/src/jswatchpoint.cpp +++ b/js/src/jswatchpoint.cpp @@ -132,7 +132,7 @@ WatchpointMap::triggerWatchpoint(JSContext *cx, HandleObject obj, HandleId id, M Value old; old.setUndefined(); if (obj->isNative()) { - if (Shape *shape = obj->nativeLookup(cx, id)) { + if (UnrootedShape shape = obj->nativeLookup(cx, id)) { if (shape->hasSlot()) old = obj->nativeGetSlot(shape->slot()); } diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index feeab9eadad..820b04ba854 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -4724,10 +4724,9 @@ xml_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id, objp.set(NULL); propp.set(NULL); } else { - Shape *shape = - js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty, - SHAPE_INVALID_SLOT, JSPROP_ENUMERATE, - 0, 0); + RootedShape shape(cx, js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty, + SHAPE_INVALID_SLOT, JSPROP_ENUMERATE, + 0, 0)); if (!shape) return JS_FALSE; @@ -4756,13 +4755,12 @@ xml_lookupElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandle return true; } - jsid id; - if (!IndexToId(cx, index, &id)) + RootedId id(cx); + if (!IndexToId(cx, index, id.address())) return false; - Shape *shape = - js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty, SHAPE_INVALID_SLOT, - JSPROP_ENUMERATE, 0, 0); + RootedShape shape(cx, js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty, + SHAPE_INVALID_SLOT, JSPROP_ENUMERATE, 0, 0)); if (!shape) return false; diff --git a/js/src/methodjit/BaseAssembler.h b/js/src/methodjit/BaseAssembler.h index 47345893e32..88eb4b56bd3 100644 --- a/js/src/methodjit/BaseAssembler.h +++ b/js/src/methodjit/BaseAssembler.h @@ -197,7 +197,7 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::MIPSRegiste loadPtr(Address(obj, JSObject::offsetOfShape()), shape); } - Jump guardShape(RegisterID objReg, Shape *shape) { + Jump guardShape(RegisterID objReg, UnrootedShape shape) { return branchPtr(NotEqual, Address(objReg, JSObject::offsetOfShape()), ImmPtr(shape)); } @@ -981,7 +981,7 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::MIPSRegiste } void loadObjProp(JSObject *obj, RegisterID objReg, - js::Shape *shape, + js::UnrootedShape shape, RegisterID typeReg, RegisterID dataReg) { if (obj->isFixedSlot(shape->slot())) @@ -1342,6 +1342,7 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::MIPSRegiste */ Jump getNewObject(JSContext *cx, RegisterID result, JSObject *templateObject) { + AutoAssertNoGC nogc; gc::AllocKind allocKind = templateObject->getAllocKind(); JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST); diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp index 8350bb2a7c1..b967adae6c9 100644 --- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -6079,7 +6079,7 @@ mjit::Compiler::jsop_aliasedVar(ScopeCoordinate sc, bool get, bool poppedAfter) for (unsigned i = 0; i < sc.hops; i++) masm.loadPayload(Address(reg, ScopeObject::offsetOfEnclosingScope()), reg); - Shape *shape = ScopeCoordinateToStaticScope(script_, PC).scopeShape(); + UnrootedShape shape = ScopeCoordinateToStaticScope(script_, PC).scopeShape(); Address addr; if (shape->numFixedSlots() <= sc.slot) { masm.loadPtr(Address(reg, JSObject::offsetOfSlots()), reg); @@ -6227,7 +6227,7 @@ mjit::Compiler::iter(unsigned flags) masm.loadPtr(Address(T1, offsetof(types::TypeObject, proto)), T1); masm.loadShape(T1, T1); masm.loadPtr(Address(nireg, offsetof(NativeIterator, shapes_array)), T2); - masm.loadPtr(Address(T2, sizeof(Shape *)), T2); + masm.loadPtr(Address(T2, sizeof(RawShape)), T2); Jump mismatchedProto = masm.branchPtr(Assembler::NotEqual, T1, T2); stubcc.linkExit(mismatchedProto, Uses(1)); @@ -6462,6 +6462,8 @@ mjit::Compiler::jsop_bindgname() bool mjit::Compiler::jsop_getgname(uint32_t index) { + AssertCanGC(); + /* Optimize undefined, NaN and Infinity. */ PropertyName *name = script_->getName(index); if (name == cx->names().undefined) { @@ -6500,9 +6502,9 @@ mjit::Compiler::jsop_getgname(uint32_t index) * then bake its address into the jitcode and guard against future * reallocation of the global object's slots. */ - js::Shape *shape = globalObj->nativeLookup(cx, NameToId(name)); + UnrootedShape shape = globalObj->nativeLookup(cx, NameToId(name)); if (shape && shape->hasDefaultGetter() && shape->hasSlot()) { - HeapSlot *value = &globalObj->getSlotRef(shape->slot()); + HeapSlot *value = &globalObj->getSlotRef(DropUnrooted(shape)->slot()); if (!value->isUndefined() && !propertyTypes->isOwnProperty(cx, globalObj->getType(cx), true)) { watchGlobalReallocation(); @@ -6626,7 +6628,7 @@ mjit::Compiler::jsop_setgname(PropertyName *name, bool popGuaranteed) types::HeapTypeSet *types = globalObj->getType(cx)->getProperty(cx, id, false); if (!types) return false; - js::Shape *shape = globalObj->nativeLookup(cx, NameToId(name)); + UnrootedShape shape = globalObj->nativeLookup(cx, NameToId(name)); if (shape && shape->hasDefaultSetter() && shape->writable() && shape->hasSlot() && !types->isOwnProperty(cx, globalObj->getType(cx), true)) { @@ -7911,6 +7913,8 @@ mjit::Compiler::BarrierState mjit::Compiler::pushAddressMaybeBarrier(Address address, JSValueType type, bool reuseBase, bool testUndefined) { + AssertCanGC(); + if (!hasTypeBarriers(PC) && !testUndefined) { frame.push(address, type, reuseBase); return BarrierState(); diff --git a/js/src/methodjit/FastOps.cpp b/js/src/methodjit/FastOps.cpp index 5ce9182f733..b7ac75f749f 100644 --- a/js/src/methodjit/FastOps.cpp +++ b/js/src/methodjit/FastOps.cpp @@ -1515,7 +1515,7 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed) ic.slowPathStart = stubcc.syncExit(Uses(3)); // Guard obj is a dense array. - Shape *shape = GetDenseArrayShape(cx, globalObj); + UnrootedShape shape = GetDenseArrayShape(cx, globalObj); if (!shape) return false; ic.shapeGuard = masm.guardShape(ic.objReg, shape); @@ -2093,7 +2093,7 @@ mjit::Compiler::jsop_getelem() } // Guard obj is a dense array. - Shape *shape = GetDenseArrayShape(cx, globalObj); + UnrootedShape shape = GetDenseArrayShape(cx, globalObj); if (!shape) return false; ic.shapeGuard = masm.guardShape(ic.objReg, shape); diff --git a/js/src/methodjit/MethodJIT.cpp b/js/src/methodjit/MethodJIT.cpp index d28ff3c2c5c..db2cc3c96ab 100644 --- a/js/src/methodjit/MethodJIT.cpp +++ b/js/src/methodjit/MethodJIT.cpp @@ -1400,12 +1400,12 @@ GetPIC(JSContext *cx, JSScript *script, jsbytecode *pc, bool constructing) return NULL; } -Shape * +UnrootedShape mjit::GetPICSingleShape(JSContext *cx, JSScript *script, jsbytecode *pc, bool constructing) { ic::PICInfo *pic = GetPIC(cx, script, pc, constructing); if (!pic) - return NULL; + return UnrootedShape(NULL); return pic->getSingleShape(); } diff --git a/js/src/methodjit/MethodJIT.h b/js/src/methodjit/MethodJIT.h index 98db4259e95..027ef8d5a98 100644 --- a/js/src/methodjit/MethodJIT.h +++ b/js/src/methodjit/MethodJIT.h @@ -1035,7 +1035,7 @@ IsLowerableFunCallOrApply(jsbytecode *pc) #endif } -Shape * +UnrootedShape GetPICSingleShape(JSContext *cx, JSScript *script, jsbytecode *pc, bool constructing); static inline void diff --git a/js/src/methodjit/MonoIC.cpp b/js/src/methodjit/MonoIC.cpp index cfdcda4d1de..96fc1593c24 100644 --- a/js/src/methodjit/MonoIC.cpp +++ b/js/src/methodjit/MonoIC.cpp @@ -68,32 +68,35 @@ ic::GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic) RecompilationMonitor monitor(f.cx); - Shape *shape = obj->nativeLookup(f.cx, NameToId(name)); - - if (monitor.recompiled()) { - stubs::Name(f); - return; - } - - if (!shape || - !shape->hasDefaultGetter() || - !shape->hasSlot()) + uint32_t slot; { - if (shape) - PatchGetFallback(f, ic); - stubs::Name(f); - return; + RootedShape shape(f.cx, obj->nativeLookup(f.cx, NameToId(name))); + + if (monitor.recompiled()) { + stubs::Name(f); + return; + } + + if (!shape || + !shape->hasDefaultGetter() || + !shape->hasSlot()) + { + if (shape) + PatchGetFallback(f, ic); + stubs::Name(f); + return; + } + slot = shape->slot(); + + /* Patch shape guard. */ + Repatcher repatcher(f.chunk()); + repatcher.repatch(ic->fastPathStart.dataLabelPtrAtOffset(ic->shapeOffset), obj->lastProperty()); + + /* Patch loads. */ + uint32_t index = obj->dynamicSlotIndex(slot); + JSC::CodeLocationLabel label = ic->fastPathStart.labelAtOffset(ic->loadStoreOffset); + repatcher.patchAddressOffsetForValueLoad(label, index * sizeof(Value)); } - uint32_t slot = shape->slot(); - - /* Patch shape guard. */ - Repatcher repatcher(f.chunk()); - repatcher.repatch(ic->fastPathStart.dataLabelPtrAtOffset(ic->shapeOffset), obj->lastProperty()); - - /* Patch loads. */ - uint32_t index = obj->dynamicSlotIndex(slot); - JSC::CodeLocationLabel label = ic->fastPathStart.labelAtOffset(ic->loadStoreOffset); - repatcher.patchAddressOffsetForValueLoad(label, index * sizeof(Value)); /* Do load anyway... this time. */ stubs::Name(f); @@ -117,14 +120,14 @@ PatchSetFallback(VMFrame &f, ic::SetGlobalNameIC *ic) } void -SetGlobalNameIC::patchInlineShapeGuard(Repatcher &repatcher, Shape *shape) +SetGlobalNameIC::patchInlineShapeGuard(Repatcher &repatcher, UnrootedShape shape) { JSC::CodeLocationDataLabelPtr label = fastPathStart.dataLabelPtrAtOffset(shapeOffset); repatcher.repatch(label, shape); } static LookupStatus -UpdateSetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic, JSObject *obj, Shape *shape) +UpdateSetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic, JSObject *obj, UnrootedShape shape) { /* Give globals a chance to appear. */ if (!shape) @@ -162,12 +165,14 @@ ic::SetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic) RecompilationMonitor monitor(f.cx); - Shape *shape = obj->nativeLookup(f.cx, NameToId(name)); + { + UnrootedShape shape = obj->nativeLookup(f.cx, NameToId(name)); - if (!monitor.recompiled()) { - LookupStatus status = UpdateSetGlobalName(f, ic, obj, shape); - if (status == Lookup_Error) - THROW(); + if (!monitor.recompiled()) { + LookupStatus status = UpdateSetGlobalName(f, ic, obj, shape); + if (status == Lookup_Error) + THROW(); + } } stubs::SetName(f, name); diff --git a/js/src/methodjit/MonoIC.h b/js/src/methodjit/MonoIC.h index 8a20ea215c7..4df71bf7d65 100644 --- a/js/src/methodjit/MonoIC.h +++ b/js/src/methodjit/MonoIC.h @@ -116,7 +116,7 @@ struct SetGlobalNameIC : public GlobalNameIC /* SET only. */ ValueRemat vr; /* RHS value. */ - void patchInlineShapeGuard(Repatcher &repatcher, Shape *shape); + void patchInlineShapeGuard(Repatcher &repatcher, UnrootedShape shape); }; void JS_FASTCALL GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic); diff --git a/js/src/methodjit/PolyIC.cpp b/js/src/methodjit/PolyIC.cpp index 1f997ebd853..e669d307488 100644 --- a/js/src/methodjit/PolyIC.cpp +++ b/js/src/methodjit/PolyIC.cpp @@ -189,7 +189,7 @@ class SetPropCompiler : public PICStubCompiler repatcher.relink(pic.slowPathCall, target); } - LookupStatus patchInline(Shape *shape) + LookupStatus patchInline(UnrootedShape shape) { JS_ASSERT(!pic.inlinePathPatched); JaegerSpew(JSpew_PICs, "patch setprop inline at %p\n", pic.fastPathStart.executableAddress()); @@ -249,7 +249,7 @@ class SetPropCompiler : public PICStubCompiler repatcher.relink(label.jumpAtOffset(secondGuardOffset), cs); } - LookupStatus generateStub(Shape *initialShape, Shape *shape, bool adding) + LookupStatus generateStub(UnrootedShape initialShape, UnrootedShape shape, bool adding) { if (hadGC()) return Lookup_Uncacheable; @@ -510,7 +510,7 @@ class SetPropCompiler : public PICStubCompiler proto = proto->getProto(); } - Shape *initialShape = obj->lastProperty(); + RootedShape initialShape(cx, obj->lastProperty()); uint32_t slots = obj->numDynamicSlots(); unsigned flags = 0; @@ -521,9 +521,8 @@ class SetPropCompiler : public PICStubCompiler * populate the slot to satisfy the method invariant (in case we * hit an early return below). */ - shape = - obj->putProperty(cx, name, getter, clasp->setProperty, - SHAPE_INVALID_SLOT, JSPROP_ENUMERATE, flags, 0); + shape = JSObject::putProperty(cx, obj, name, getter, clasp->setProperty, + SHAPE_INVALID_SLOT, JSPROP_ENUMERATE, flags, 0); if (!shape) return error(); @@ -1016,7 +1015,7 @@ class GetPropCompiler : public PICStubCompiler return Lookup_Cacheable; } - LookupStatus patchInline(JSObject *holder, Shape *shape) + LookupStatus patchInline(JSObject *holder, UnrootedShape shape) { spew("patch", "inline"); Repatcher repatcher(f.chunk()); @@ -1051,7 +1050,7 @@ class GetPropCompiler : public PICStubCompiler } /* For JSPropertyOp getters. */ - void generateGetterStub(Assembler &masm, Shape *shape, jsid userid, + void generateGetterStub(Assembler &masm, UnrootedShape shape, jsid userid, Label start, Vector &shapeMismatches) { AutoAssertNoGC nogc; @@ -1163,7 +1162,7 @@ class GetPropCompiler : public PICStubCompiler } /* For getters backed by a JSNative. */ - void generateNativeGetterStub(Assembler &masm, Shape *shape, + void generateNativeGetterStub(Assembler &masm, UnrootedShape shape, Label start, Vector &shapeMismatches) { AutoAssertNoGC nogc; @@ -1704,7 +1703,7 @@ class ScopeNameCompiler : public PICStubCompiler JS_ASSERT(obj == getprop.holder); JS_ASSERT(getprop.holder != &scopeChain->global()); - Shape *shape = getprop.shape; + UnrootedShape shape = getprop.shape; if (!shape->hasDefaultGetter()) return disable("unhandled callobj sprop getter"); @@ -1833,7 +1832,17 @@ class ScopeNameCompiler : public PICStubCompiler Rooted normalized(cx, obj); if (obj->isWith() && !shape->hasDefaultGetter()) normalized = &obj->asWith().object(); - NATIVE_GET(cx, normalized, holder, shape, 0, vp.address(), return false); + if (shape->isDataDescriptor() && shape->hasDefaultGetter()) { + /* Fast path for Object instance properties. */ + JS_ASSERT(shape->slot() != SHAPE_INVALID_SLOT || !shape->hasDefaultSetter()); + if (shape->slot() != SHAPE_INVALID_SLOT) + vp.set(holder->nativeGetSlot(shape->slot())); + else + vp.setUndefined(); + } else { + if (!js_NativeGet(cx, normalized, holder, shape, 0, vp)) + return false; + } return true; } }; @@ -2402,7 +2411,7 @@ GetElementIC::attachGetProp(VMFrame &f, HandleObject obj, HandleValue v, HandleP } // Load the value. - Shape *shape = getprop.shape; + RootedShape shape(cx, getprop.shape); masm.loadObjProp(holder, holderReg, shape, typeReg, objReg); Jump done = masm.jump(); diff --git a/js/src/methodjit/PolyIC.h b/js/src/methodjit/PolyIC.h index 157b1534d14..7117bd2e5ec 100644 --- a/js/src/methodjit/PolyIC.h +++ b/js/src/methodjit/PolyIC.h @@ -489,14 +489,14 @@ struct PICInfo : public BasePolyIC { public: void purge(Repatcher &repatcher); - void setInlinePathShape(Shape *shape) { + void setInlinePathShape(UnrootedShape shape) { JS_ASSERT(!inlinePathShape_); inlinePathShape_ = shape; } - Shape *getSingleShape() { + UnrootedShape getSingleShape() { if (disabled || hadUncacheable || stubsGenerated > 0) - return NULL; + return UnrootedShape(NULL); return inlinePathShape_; } diff --git a/js/src/methodjit/StubCalls-inl.h b/js/src/methodjit/StubCalls-inl.h index b62cf8936d2..462d2513c26 100644 --- a/js/src/methodjit/StubCalls-inl.h +++ b/js/src/methodjit/StubCalls-inl.h @@ -29,23 +29,8 @@ ReportAtomNotDefined(JSContext *cx, JSAtom *atom) js_ReportIsNotDefined(cx, printable.ptr()); } -#define NATIVE_GET(cx,obj,pobj,shape,getHow,vp,onerr) \ - JS_BEGIN_MACRO \ - if (shape->isDataDescriptor() && shape->hasDefaultGetter()) { \ - /* Fast path for Object instance properties. */ \ - JS_ASSERT((shape)->slot() != SHAPE_INVALID_SLOT || \ - !shape->hasDefaultSetter()); \ - if (((shape)->slot() != SHAPE_INVALID_SLOT)) \ - *(vp) = (pobj)->nativeGetSlot((shape)->slot()); \ - else \ - (vp)->setUndefined(); \ - } else { \ - if (!js_NativeGet(cx, obj, pobj, shape, getHow, vp)) \ - onerr; \ - } \ - JS_END_MACRO - -}} +} /* namespace mjit */ +} /* namespace js */ #endif /* jslogic_h__ */ diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 0d5d3580345..9e22913b01b 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2776,8 +2776,8 @@ CopyProperty(JSContext *cx, HandleObject obj, HandleObject referent, HandleId id RootedValue value(cx, desc.value); objp.set(obj); - return !!DefineNativeProperty(cx, obj, id, value, desc.getter, desc.setter, - desc.attrs, propFlags, desc.shortid); + return DefineNativeProperty(cx, obj, id, value, desc.getter, desc.setter, + desc.attrs, propFlags, desc.shortid); } static JSBool diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 62bc35f1dca..1e4e3ea6d34 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -849,7 +849,7 @@ Debugger::parseResumptionValue(Maybe &ac, bool ok, const Value /* Check that rv is {return: val} or {throw: val}. */ JSContext *cx = ac.ref().context(); Rooted obj(cx); - Shape *shape; + RootedShape shape(cx); jsid returnId = NameToId(cx->names().return_); jsid throwId = NameToId(cx->names().throw_); bool okResumption = rv.isObject(); @@ -869,8 +869,10 @@ Debugger::parseResumptionValue(Maybe &ac, bool ok, const Value return handleUncaughtException(ac, vp, callHook); } - if (!js_NativeGet(cx, obj, obj, shape, 0, vp) || !unwrapDebuggeeValue(cx, vp)) - return handleUncaughtException(ac, vp, callHook); + RootedValue v(cx, *vp); + if (!js_NativeGet(cx, obj, obj, shape, 0, &v) || !unwrapDebuggeeValue(cx, v.address())) + return handleUncaughtException(ac, v.address(), callHook); + *vp = v; ac.destroy(); if (!cx->compartment->wrap(cx, vp)) { diff --git a/js/src/vm/ObjectImpl-inl.h b/js/src/vm/ObjectImpl-inl.h index f85d057a7d3..23a89007a0c 100644 --- a/js/src/vm/ObjectImpl-inl.h +++ b/js/src/vm/ObjectImpl-inl.h @@ -40,25 +40,25 @@ Debug_SetSlotRangeToCrashOnTouch(HeapSlot *begin, HeapSlot *end) } // namespace js -inline js::Shape * +inline js::UnrootedShape js::ObjectImpl::nativeLookup(JSContext *cx, PropertyId pid) { return nativeLookup(cx, pid.asId()); } -inline js::Shape * +inline js::UnrootedShape js::ObjectImpl::nativeLookup(JSContext *cx, PropertyName *name) { return nativeLookup(cx, PropertyId(name)); } -inline js::Shape * +inline js::UnrootedShape js::ObjectImpl::nativeLookupNoAllocation(PropertyId pid) { return nativeLookupNoAllocation(pid.asId()); } -inline js::Shape * +inline js::UnrootedShape js::ObjectImpl::nativeLookupNoAllocation(PropertyName *name) { return nativeLookupNoAllocation(PropertyId(name)); diff --git a/js/src/vm/ObjectImpl.cpp b/js/src/vm/ObjectImpl.cpp index 5a5e57bbd19..66e4076f6cc 100644 --- a/js/src/vm/ObjectImpl.cpp +++ b/js/src/vm/ObjectImpl.cpp @@ -164,8 +164,8 @@ js::ObjectImpl::checkShapeConsistency() MOZ_ASSERT(isNative()); - Shape *shape = lastProperty(); - Shape *prev = NULL; + UnrootedShape shape = lastProperty(); + UnrootedShape prev = NULL; if (inDictionaryMode()) { MOZ_ASSERT(shape->hasTable()); @@ -177,7 +177,7 @@ js::ObjectImpl::checkShapeConsistency() } for (int n = throttle; --n >= 0 && shape->parent; shape = shape->parent) { - MOZ_ASSERT_IF(shape != lastProperty(), !shape->hasTable()); + MOZ_ASSERT_IF(lastProperty() != shape, !shape->hasTable()); Shape **spp = table.search(shape->propid(), false); MOZ_ASSERT(SHAPE_FETCH(spp) == shape); @@ -187,7 +187,7 @@ js::ObjectImpl::checkShapeConsistency() for (int n = throttle; --n >= 0 && shape; shape = shape->parent) { MOZ_ASSERT_IF(shape->slot() != SHAPE_INVALID_SLOT, shape->slot() < slotSpan()); if (!prev) { - MOZ_ASSERT(shape == lastProperty()); + MOZ_ASSERT(lastProperty() == shape); MOZ_ASSERT(shape->listp == &shape_); } else { MOZ_ASSERT(shape->listp == &prev->parent); @@ -257,15 +257,16 @@ js::ObjectImpl::slotInRange(uint32_t slot, SentinelAllowed sentinel) const */ MOZ_NEVER_INLINE #endif -Shape * -js::ObjectImpl::nativeLookup(JSContext *cx, jsid id) +UnrootedShape +js::ObjectImpl::nativeLookup(JSContext *cx, jsid idArg) { MOZ_ASSERT(isNative()); Shape **spp; + RootedId id(cx, idArg); return Shape::search(cx, lastProperty(), id, &spp); } -Shape * +UnrootedShape js::ObjectImpl::nativeLookupNoAllocation(jsid id) { MOZ_ASSERT(isNative()); @@ -503,8 +504,11 @@ js::GetOwnProperty(JSContext *cx, Handle obj, PropertyId pid_, unsi return false; } - Shape *shape = obj->nativeLookup(cx, pid); + /* |shape| is always set /after/ a GC. */ + UnrootedShape shape = obj->nativeLookup(cx, pid); if (!shape) { + DropUnrooted(shape); + /* Not found: attempt to resolve it. */ Class *clasp = obj->getClass(); JSResolveOp resolve = clasp->resolve; diff --git a/js/src/vm/ObjectImpl.h b/js/src/vm/ObjectImpl.h index 4953c0a10a7..41f3aade817 100644 --- a/js/src/vm/ObjectImpl.h +++ b/js/src/vm/ObjectImpl.h @@ -24,6 +24,7 @@ namespace js { class Debugger; class ObjectImpl; +ForwardDeclare(Shape); class AutoPropDescArrayRooter; @@ -358,7 +359,7 @@ class ElementsHeader } dense; class { friend class SparseElementsHeader; - Shape * shape; + RawShape shape; } sparse; class { friend class ArrayBufferElementsHeader; @@ -449,7 +450,7 @@ class DenseElementsHeader : public ElementsHeader class SparseElementsHeader : public ElementsHeader { public: - Shape * shape() { + UnrootedShape shape() { MOZ_ASSERT(ElementsHeader::isSparseElements()); return sparse.shape; } @@ -1155,13 +1156,13 @@ class ObjectImpl : public gc::Cell /* Compute dynamicSlotsCount() for this object. */ inline uint32_t numDynamicSlots() const; - Shape * nativeLookup(JSContext *cx, jsid id); - inline Shape * nativeLookup(JSContext *cx, PropertyId pid); - inline Shape * nativeLookup(JSContext *cx, PropertyName *name); + UnrootedShape nativeLookup(JSContext *cx, jsid id); + inline UnrootedShape nativeLookup(JSContext *cx, PropertyId pid); + inline UnrootedShape nativeLookup(JSContext *cx, PropertyName *name); - Shape * nativeLookupNoAllocation(jsid id); - inline Shape * nativeLookupNoAllocation(PropertyId pid); - inline Shape * nativeLookupNoAllocation(PropertyName *name); + UnrootedShape nativeLookupNoAllocation(jsid id); + inline UnrootedShape nativeLookupNoAllocation(PropertyId pid); + inline UnrootedShape nativeLookupNoAllocation(PropertyName *name); inline bool nativeContains(JSContext *cx, Handle id); inline bool nativeContains(JSContext *cx, Handle name); diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index 83dd1fca194..35aefb7fb79 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -322,7 +322,7 @@ RegExpObject::createShared(JSContext *cx, RegExpGuard *g) return true; } -Shape * +UnrootedShape RegExpObject::assignInitialShape(JSContext *cx) { JS_ASSERT(isRegExp()); @@ -338,27 +338,20 @@ RegExpObject::assignInitialShape(JSContext *cx) RootedObject self(cx, this); /* The lastIndex property alone is writable but non-configurable. */ - if (!addDataProperty(cx, NameToId(cx->names().lastIndex), - LAST_INDEX_SLOT, JSPROP_PERMANENT)) - { - return NULL; - } + if (!addDataProperty(cx, NameToId(cx->names().lastIndex), LAST_INDEX_SLOT, JSPROP_PERMANENT)) + return UnrootedShape(NULL); /* Remaining instance properties are non-writable and non-configurable. */ - if (!self->addDataProperty(cx, NameToId(cx->names().source), - SOURCE_SLOT, JSPROP_PERMANENT | JSPROP_READONLY) || - !self->addDataProperty(cx, NameToId(cx->names().global), - GLOBAL_FLAG_SLOT, JSPROP_PERMANENT | JSPROP_READONLY) || - !self->addDataProperty(cx, NameToId(cx->names().ignoreCase), - IGNORE_CASE_FLAG_SLOT, JSPROP_PERMANENT | JSPROP_READONLY) || - !self->addDataProperty(cx, NameToId(cx->names().multiline), - MULTILINE_FLAG_SLOT, JSPROP_PERMANENT | JSPROP_READONLY)) - { - return NULL; - } - - return self->addDataProperty(cx, NameToId(cx->names().sticky), - STICKY_FLAG_SLOT, JSPROP_PERMANENT | JSPROP_READONLY); + unsigned attrs = JSPROP_PERMANENT | JSPROP_READONLY; + if (!self->addDataProperty(cx, NameToId(cx->names().source), SOURCE_SLOT, attrs)) + return UnrootedShape(NULL); + if (!self->addDataProperty(cx, NameToId(cx->names().global), GLOBAL_FLAG_SLOT, attrs)) + return UnrootedShape(NULL); + if (!self->addDataProperty(cx, NameToId(cx->names().ignoreCase), IGNORE_CASE_FLAG_SLOT, attrs)) + return UnrootedShape(NULL); + if (!self->addDataProperty(cx, NameToId(cx->names().multiline), MULTILINE_FLAG_SLOT, attrs)) + return UnrootedShape(NULL); + return self->addDataProperty(cx, NameToId(cx->names().sticky), STICKY_FLAG_SLOT, attrs); } inline bool @@ -371,10 +364,11 @@ RegExpObject::init(JSContext *cx, HandleAtom source, RegExpFlag flags) if (!assignInitialShape(cx)) return false; } else { - Shape *shape = assignInitialShape(cx); + RootedShape shape(cx, assignInitialShape(cx)); if (!shape) return false; - EmptyShape::insertInitialShape(cx, shape, self->getProto()); + RootedObject proto(cx, self->getProto()); + EmptyShape::insertInitialShape(cx, shape, proto); } JS_ASSERT(!self->nativeEmpty()); } diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h index f605d5dd445..c3b580ec952 100644 --- a/js/src/vm/RegExpObject.h +++ b/js/src/vm/RegExpObject.h @@ -405,7 +405,7 @@ class RegExpObject : public JSObject * encoding their initial properties. Return the shape after * changing this regular expression object's last property to it. */ - Shape *assignInitialShape(JSContext *cx); + UnrootedShape assignInitialShape(JSContext *cx); inline bool init(JSContext *cx, HandleAtom source, RegExpFlag flags); diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 604549361d8..c2fbd4cf5dd 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -58,12 +58,14 @@ StaticScopeIter::hasDynamicScopeObject() const : obj->toFunction()->isHeavyweight(); } -Shape * +UnrootedShape StaticScopeIter::scopeShape() const { JS_ASSERT(hasDynamicScopeObject()); JS_ASSERT(type() != NAMED_LAMBDA); - return type() == BLOCK ? block().lastProperty() : funScript()->bindings.callObjShape(); + return type() == BLOCK + ? UnrootedShape(block().lastProperty()) + : funScript()->bindings.callObjShape(); } StaticScopeIter::Type @@ -303,8 +305,8 @@ DeclEnvObject::createTemplateObject(JSContext *cx, HandleFunction fun) Rooted id(cx, AtomToId(fun->atom())); Class *clasp = obj->getClass(); unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY; - if (!obj->putProperty(cx, id, clasp->getProperty, clasp->setProperty, - lambdaSlot(), attrs, 0, 0)) + if (!JSObject::putProperty(cx, obj, id, clasp->getProperty, clasp->setProperty, + lambdaSlot(), attrs, 0, 0)) { return NULL; } @@ -689,7 +691,7 @@ StaticBlockObject::create(JSContext *cx) return &obj->asStaticBlock(); } -/* static */ Shape * +/* static */ UnrootedShape StaticBlockObject::addVar(JSContext *cx, Handle block, HandleId id, int index, bool *redeclared) { @@ -701,7 +703,7 @@ StaticBlockObject::addVar(JSContext *cx, Handle block, Handl Shape **spp; if (Shape::search(cx, block->lastProperty(), id, &spp, true)) { *redeclared = true; - return NULL; + return UnrootedShape(NULL); } /* @@ -709,10 +711,10 @@ StaticBlockObject::addVar(JSContext *cx, Handle block, Handl * block's shape later. */ uint32_t slot = JSSLOT_FREE(&BlockClass) + index; - return block->addPropertyInternal(cx, id, /* getter = */ NULL, /* setter = */ NULL, - slot, JSPROP_ENUMERATE | JSPROP_PERMANENT, - Shape::HAS_SHORTID, index, spp, - /* allowDictionary = */ false); + return JSObject::addPropertyInternal(cx, block, id, /* getter = */ NULL, /* setter = */ NULL, + slot, JSPROP_ENUMERATE | JSPROP_PERMANENT, + Shape::HAS_SHORTID, index, spp, + /* allowDictionary = */ false); } Class js::BlockClass = { @@ -800,7 +802,7 @@ js::XDRStaticBlockObject(XDRState *xdr, HandleObject enclosingScope, Handl return false; for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) { - Shape *shape = &r.front(); + UnrootedShape shape = &r.front(); shapes[shape->shortid()] = shape; } @@ -808,18 +810,21 @@ js::XDRStaticBlockObject(XDRState *xdr, HandleObject enclosingScope, Handl * XDR the block object's properties. We know that there are 'count' * properties to XDR, stored as id/shortid pairs. */ + RootedShape shape(cx); + RootedId propid(cx); + RootedAtom atom(cx); for (unsigned i = 0; i < count; i++) { - Shape *shape = shapes[i]; + shape = shapes[i]; JS_ASSERT(shape->hasDefaultGetter()); JS_ASSERT(unsigned(shape->shortid()) == i); - jsid propid = shape->propid(); + propid = shape->propid(); JS_ASSERT(JSID_IS_ATOM(propid) || JSID_IS_INT(propid)); /* The empty string indicates an int id. */ - RootedAtom atom(cx, JSID_IS_ATOM(propid) - ? JSID_TO_ATOM(propid) - : cx->runtime->emptyString); + atom = JSID_IS_ATOM(propid) + ? JSID_TO_ATOM(propid) + : cx->runtime->emptyString; if (!XDRAtom(xdr, &atom)) return false; @@ -1222,7 +1227,7 @@ class DebugScopeProxy : public BaseProxyHandler /* Handle unaliased let and catch bindings at block scope. */ if (scope->isClonedBlock()) { ClonedBlockObject &block = scope->asClonedBlock(); - Shape *shape = block.lastProperty()->search(cx, id); + UnrootedShape shape = block.lastProperty()->search(cx, id); if (!shape) return false; diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index a717fecda80..b76174f6fb1 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -65,7 +65,7 @@ class StaticScopeIter /* Return whether this static scope will be on the dynamic scope chain. */ bool hasDynamicScopeObject() const; - Shape *scopeShape() const; + UnrootedShape scopeShape() const; enum Type { BLOCK, FUNCTION, NAMED_LAMBDA }; Type type() const; @@ -346,8 +346,8 @@ class StaticBlockObject : public BlockObject void initPrevBlockChainFromParser(StaticBlockObject *prev); void resetPrevBlockChainFromParser(); - static Shape *addVar(JSContext *cx, Handle block, HandleId id, - int index, bool *redeclared); + static UnrootedShape addVar(JSContext *cx, Handle block, HandleId id, + int index, bool *redeclared); }; class ClonedBlockObject : public BlockObject diff --git a/js/src/vm/String.h b/js/src/vm/String.h index a378d08f916..7b1e4e9859f 100644 --- a/js/src/vm/String.h +++ b/js/src/vm/String.h @@ -855,6 +855,7 @@ class AutoNameVector : public AutoVectorRooter JS_ALWAYS_INLINE const jschar * JSString::getChars(JSContext *cx) { + JS::AutoAssertNoGC nogc; if (JSLinearString *str = ensureLinear(cx)) return str->chars(); return NULL; @@ -863,6 +864,7 @@ JSString::getChars(JSContext *cx) JS_ALWAYS_INLINE const jschar * JSString::getCharsZ(JSContext *cx) { + JS::AutoAssertNoGC nogc; if (JSFlatString *str = ensureFlat(cx)) return str->chars(); return NULL; @@ -871,6 +873,7 @@ JSString::getCharsZ(JSContext *cx) JS_ALWAYS_INLINE JSLinearString * JSString::ensureLinear(JSContext *cx) { + JS::AutoAssertNoGC nogc; return isLinear() ? &asLinear() : asRope().flatten(cx); @@ -879,6 +882,7 @@ JSString::ensureLinear(JSContext *cx) JS_ALWAYS_INLINE JSFlatString * JSString::ensureFlat(JSContext *cx) { + JS::AutoAssertNoGC nogc; return isFlat() ? &asFlat() : isDependent() @@ -889,6 +893,7 @@ JSString::ensureFlat(JSContext *cx) JS_ALWAYS_INLINE JSStableString * JSString::ensureStable(JSContext *maybecx) { + JS::AutoAssertNoGC nogc; if (isRope()) { JSFlatString *flat = asRope().flatten(maybecx); if (!flat) diff --git a/js/src/vm/StringObject-inl.h b/js/src/vm/StringObject-inl.h index e991aeba444..9d749c9ebff 100644 --- a/js/src/vm/StringObject-inl.h +++ b/js/src/vm/StringObject-inl.h @@ -22,6 +22,7 @@ namespace js { inline bool StringObject::init(JSContext *cx, HandleString str) { + AssertCanGC(); JS_ASSERT(gc::GetGCKindSlots(getAllocKind()) == 2); Rooted self(cx, this); @@ -31,10 +32,11 @@ StringObject::init(JSContext *cx, HandleString str) if (!assignInitialShape(cx)) return false; } else { - Shape *shape = assignInitialShape(cx); + RootedShape shape(cx, assignInitialShape(cx)); if (!shape) return false; - EmptyShape::insertInitialShape(cx, shape, self->getProto()); + RootedObject proto(cx, self->getProto()); + EmptyShape::insertInitialShape(cx, shape, proto); } } diff --git a/js/src/vm/StringObject.h b/js/src/vm/StringObject.h index edb0072d9c2..a12c73737f7 100644 --- a/js/src/vm/StringObject.h +++ b/js/src/vm/StringObject.h @@ -66,7 +66,7 @@ class StringObject : public JSObject * encodes the initial length property. Return the shape after changing * this String object's last property to it. */ - Shape *assignInitialShape(JSContext *cx); + UnrootedShape assignInitialShape(JSContext *cx); }; } // namespace js