Bug 832972 - Reduce cost of exact stack rooting during name operations, clean up some GC allocation methods, r=terrence.

This commit is contained in:
Brian Hackett 2013-01-23 15:22:10 -07:00
parent 6aced240ae
commit 5c1084be65
28 changed files with 319 additions and 259 deletions

View File

@ -801,10 +801,94 @@ class SkipRoot
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
/* Interface substitute for Rooted<T> which does not root the variable's memory. */
template <typename T>
class FakeRooted : public RootedBase<T>
{
public:
FakeRooted(JSContext *cx
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: ptr(RootMethods<T>::initial())
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
FakeRooted(JSContext *cx, T initial
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: ptr(initial)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
template <typename S>
FakeRooted(JSContext *cx, const Unrooted<S> &initial
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: ptr(static_cast<S>(initial))
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
operator T() const { return ptr; }
T operator->() const { return ptr; }
T *address() { return &ptr; }
const T *address() const { return &ptr; }
T &get() { return ptr; }
const T &get() const { return ptr; }
T &operator=(T value) {
JS_ASSERT(!RootMethods<T>::poisoned(value));
ptr = value;
return ptr;
}
bool operator!=(const T &other) { return ptr != other; }
bool operator==(const T &other) { return ptr == other; }
private:
T ptr;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
FakeRooted(const FakeRooted &) MOZ_DELETE;
};
/* Interface substitute for MutableHandle<T> which is not required to point to rooted memory. */
template <typename T>
class FakeMutableHandle : public js::MutableHandleBase<T>
{
public:
FakeMutableHandle(T *t) {
ptr = t;
}
void set(T v) {
JS_ASSERT(!js::RootMethods<T>::poisoned(v));
*ptr = v;
}
T *address() const { return ptr; }
T get() const { return *ptr; }
operator T() const { return get(); }
T operator->() const { return get(); }
private:
FakeMutableHandle() {}
T *ptr;
template <typename S>
void operator=(S v) MOZ_DELETE;
};
/*
* Types for a variable that either should or shouldn't be rooted, depending on
* the template parameter Rooted. Used for implementing functions that can
* operate on either rooted or unrooted data.
*
* The toHandle() and toMutableHandle() functions are for calling functions
* which require handle types and are only called in the ALLOW_GC case. These
* allow the calling code to type check.
*/
enum AllowGC {
DONT_ALLOW_GC = 0,
@ -818,15 +902,35 @@ class MaybeRooted
template <typename T> class MaybeRooted<T, ALLOW_GC>
{
public:
typedef Rooted<T> RootType;
typedef Handle<T> HandleType;
typedef Rooted<T> RootType;
typedef MutableHandle<T> MutableHandleType;
static inline Handle<T> toHandle(HandleType v) {
return v;
}
static inline MutableHandle<T> toMutableHandle(MutableHandleType v) {
return v;
}
};
template <typename T> class MaybeRooted<T, DONT_ALLOW_GC>
{
public:
typedef T RootType;
typedef T HandleType;
typedef FakeRooted<T> RootType;
typedef FakeMutableHandle<T> MutableHandleType;
static inline Handle<T> toHandle(HandleType v) {
JS_NOT_REACHED("Bad conversion");
return Handle<T>::fromMarkedLocation(NULL);
}
static inline MutableHandle<T> toMutableHandle(MutableHandleType v) {
JS_NOT_REACHED("Bad conversion");
return MutableHandle<T>::fromMarkedLocation(NULL);
}
};
} /* namespace js */

View File

@ -323,7 +323,7 @@ IonCode::New(JSContext *cx, uint8_t *code, uint32_t bufferSize, JSC::ExecutableP
{
AssertCanGC();
IonCode *codeObj = gc::NewGCThing<IonCode>(cx, gc::FINALIZE_IONCODE, sizeof(IonCode));
IonCode *codeObj = gc::NewGCThing<IonCode, ALLOW_GC>(cx, gc::FINALIZE_IONCODE, sizeof(IonCode));
if (!codeObj) {
pool->release();
return NULL;

View File

@ -392,7 +392,7 @@ struct GetNativePropertyStub
JS_ASSERT_IF(expando, expando->isNative() && expando->getProto() == NULL);
masm.loadValue(expandoAddr, tempVal);
if (expando && expando->nativeLookupNoAllocation(propName)) {
if (expando && expando->nativeLookup(cx, propName)) {
// Reference object has an expando that doesn't define the name.
// Check incoming object's expando and make sure it's an object.

View File

@ -116,7 +116,7 @@ InvokeFunction(JSContext *cx, HandleFunction fun0, uint32_t argc, Value *argv, V
JSObject *
NewGCThing(JSContext *cx, gc::AllocKind allocKind, size_t thingSize)
{
return gc::NewGCThing<JSObject>(cx, allocKind, thingSize);
return gc::NewGCThing<JSObject, ALLOW_GC>(cx, allocKind, thingSize);
}
bool

View File

@ -106,7 +106,7 @@ NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entry_)
JS_ASSERT(unsigned(entry_) < mozilla::ArrayLength(entries));
Entry *entry = &entries[entry_];
JSObject *obj = js_TryNewGCObject(cx, entry->kind);
JSObject *obj = js_NewGCObject<DONT_ALLOW_GC>(cx, entry->kind);
if (obj) {
copyCachedToObject(obj, reinterpret_cast<JSObject *>(&entry->templateObject));
Probes::createObject(cx, obj);

View File

@ -1449,6 +1449,7 @@ RunLastDitchGC(JSContext *cx, gcreason::Reason reason)
GC(rt, GC_NORMAL, reason);
}
template <AllowGC allowGC>
/* static */ void *
ArenaLists::refillFreeList(JSContext *cx, AllocKind thingKind)
{
@ -1458,7 +1459,9 @@ ArenaLists::refillFreeList(JSContext *cx, AllocKind thingKind)
JSRuntime *rt = comp->rt;
JS_ASSERT(!rt->isHeapBusy());
bool runGC = rt->gcIncrementalState != NO_INCREMENTAL && comp->gcBytes > comp->gcTriggerBytes;
bool runGC = rt->gcIncrementalState != NO_INCREMENTAL &&
comp->gcBytes > comp->gcTriggerBytes &&
allowGC;
for (;;) {
if (JS_UNLIKELY(runGC)) {
PrepareCompartmentForGC(comp);
@ -1492,6 +1495,9 @@ ArenaLists::refillFreeList(JSContext *cx, AllocKind thingKind)
rt->gcHelperThread.waitBackgroundSweepEnd();
}
if (!allowGC)
return NULL;
/*
* We failed to allocate. Run the GC if we haven't done it already.
* Otherwise report OOM.
@ -1501,10 +1507,17 @@ ArenaLists::refillFreeList(JSContext *cx, AllocKind thingKind)
runGC = true;
}
JS_ASSERT(allowGC);
js_ReportOutOfMemory(cx);
return NULL;
}
template void *
ArenaLists::refillFreeList<DONT_ALLOW_GC>(JSContext *cx, AllocKind thingKind);
template void *
ArenaLists::refillFreeList<ALLOW_GC>(JSContext *cx, AllocKind thingKind);
JSGCTraceKind
js_GetGCThingTraceKind(void *thing)
{
@ -4769,6 +4782,6 @@ js_NewGCXML(JSContext *cx)
if (!cx->runningWithTrustedPrincipals())
++sE4XObjectsCreated;
return NewGCThing<JSXML>(cx, js::gc::FINALIZE_XML, sizeof(JSXML));
return NewGCThing<JSXML, ALLOW_GC>(cx, js::gc::FINALIZE_XML, sizeof(JSXML));
}
#endif

View File

@ -411,6 +411,7 @@ struct ArenaLists {
return freeLists[thingKind].allocate(thingSize);
}
template <AllowGC allowGC>
static void *refillFreeList(JSContext *cx, AllocKind thingKind);
void checkEmptyFreeLists() {

View File

@ -476,11 +476,13 @@ class GCCompartmentGroupIter {
* in the partially initialized thing.
*/
template <typename T>
template <typename T, AllowGC allowGC>
inline T *
NewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
{
AssertCanGC();
if (allowGC)
AssertCanGC();
JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind));
JS_ASSERT_IF(cx->compartment == cx->runtime->atomsCompartment,
kind == FINALIZE_STRING ||
@ -493,16 +495,17 @@ NewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
JS_OOM_POSSIBLY_FAIL_REPORT(cx);
#ifdef JS_GC_ZEAL
if (cx->runtime->needZealousGC())
if (cx->runtime->needZealousGC() && allowGC)
js::gc::RunDebugGC(cx);
#endif
MaybeCheckStackRoots(cx, /* relax = */ false);
if (allowGC)
MaybeCheckStackRoots(cx, /* relax = */ false);
JSCompartment *comp = cx->compartment;
T *t = static_cast<T *>(comp->arenas.allocateFromFreeList(kind, thingSize));
if (!t)
t = static_cast<T *>(js::gc::ArenaLists::refillFreeList(cx, kind));
t = static_cast<T *>(js::gc::ArenaLists::refillFreeList<allowGC>(cx, kind));
JS_ASSERT_IF(t && comp->wasGCStarted() && (comp->isGCMarking() || comp->isGCSweeping()),
t->arenaHeader()->allocatedDuringIncremental);
@ -515,36 +518,6 @@ NewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
return t;
}
/* Alternate form which allocates a GC thing if doing so cannot trigger a GC. */
template <typename T>
inline T *
TryNewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
{
AutoAssertNoGC nogc;
JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind));
JS_ASSERT_IF(cx->compartment == cx->runtime->atomsCompartment,
kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING);
JS_ASSERT(!cx->runtime->isHeapBusy());
JS_ASSERT(!cx->runtime->noGCOrAllocationCheck);
#ifdef JS_GC_ZEAL
if (cx->runtime->needZealousGC())
return NULL;
#endif
JSCompartment *comp = cx->compartment;
T *t = static_cast<T *>(comp->arenas.allocateFromFreeList(kind, thingSize));
JS_ASSERT_IF(t && comp->wasGCStarted() && (comp->isGCMarking() || comp->isGCSweeping()),
t->arenaHeader()->allocatedDuringIncremental);
#if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
if (cx->runtime->gcVerifyPostData && IsNurseryAllocable(kind) && !IsAtomsCompartment(comp))
comp->gcNursery.insertPointer(t);
#endif
return t;
}
/*
* Instances of this class set the |JSRuntime::suppressGC| flag for the duration
* that they are live. Use of this class is highly discouraged. Please carefully
@ -577,67 +550,52 @@ class AutoSuppressGC
} /* namespace gc */
} /* namespace js */
template <js::AllowGC allowGC>
inline JSObject *
js_NewGCObject(JSContext *cx, js::gc::AllocKind kind)
{
JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
return js::gc::NewGCThing<JSObject>(cx, kind, js::gc::Arena::thingSize(kind));
}
inline JSObject *
js_TryNewGCObject(JSContext *cx, js::gc::AllocKind kind)
{
JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
return js::gc::TryNewGCThing<JSObject>(cx, kind, js::gc::Arena::thingSize(kind));
return js::gc::NewGCThing<JSObject, allowGC>(cx, kind, js::gc::Arena::thingSize(kind));
}
template <js::AllowGC allowGC>
inline JSString *
js_NewGCString(JSContext *cx)
{
return js::gc::NewGCThing<JSString>(cx, js::gc::FINALIZE_STRING, sizeof(JSString));
}
inline JSString *
js_TryNewGCString(JSContext *cx)
{
return js::gc::TryNewGCThing<JSString>(cx, js::gc::FINALIZE_STRING, sizeof(JSString));
return js::gc::NewGCThing<JSString, allowGC>(cx, js::gc::FINALIZE_STRING, sizeof(JSString));
}
template <js::AllowGC allowGC>
inline JSShortString *
js_NewGCShortString(JSContext *cx)
{
return js::gc::NewGCThing<JSShortString>(cx, js::gc::FINALIZE_SHORT_STRING, sizeof(JSShortString));
}
inline JSShortString *
js_TryNewGCShortString(JSContext *cx)
{
return js::gc::TryNewGCThing<JSShortString>(cx, js::gc::FINALIZE_SHORT_STRING, sizeof(JSShortString));
return js::gc::NewGCThing<JSShortString, allowGC>(cx, js::gc::FINALIZE_SHORT_STRING, sizeof(JSShortString));
}
inline JSExternalString *
js_NewGCExternalString(JSContext *cx)
{
return js::gc::NewGCThing<JSExternalString>(cx, js::gc::FINALIZE_EXTERNAL_STRING,
sizeof(JSExternalString));
return js::gc::NewGCThing<JSExternalString, js::ALLOW_GC>(cx, js::gc::FINALIZE_EXTERNAL_STRING,
sizeof(JSExternalString));
}
inline JSScript *
js_NewGCScript(JSContext *cx)
{
return js::gc::NewGCThing<JSScript>(cx, js::gc::FINALIZE_SCRIPT, sizeof(JSScript));
return js::gc::NewGCThing<JSScript, js::ALLOW_GC>(cx, js::gc::FINALIZE_SCRIPT, sizeof(JSScript));
}
inline js::UnrootedShape
js_NewGCShape(JSContext *cx)
{
return js::gc::NewGCThing<js::Shape>(cx, js::gc::FINALIZE_SHAPE, sizeof(js::Shape));
return js::gc::NewGCThing<js::Shape, js::ALLOW_GC>(cx, js::gc::FINALIZE_SHAPE, sizeof(js::Shape));
}
template <js::AllowGC allowGC>
inline js::UnrootedBaseShape
js_NewGCBaseShape(JSContext *cx)
{
return js::gc::NewGCThing<js::BaseShape>(cx, js::gc::FINALIZE_BASE_SHAPE, sizeof(js::BaseShape));
return js::gc::NewGCThing<js::BaseShape, allowGC>(cx, js::gc::FINALIZE_BASE_SHAPE, sizeof(js::BaseShape));
}
#if JS_HAS_XML_SUPPORT

View File

@ -2279,7 +2279,7 @@ TypeCompartment::newTypeObject(JSContext *cx, Class *clasp, Handle<TaggedProto>
{
JS_ASSERT_IF(proto.isObject(), cx->compartment == proto.toObject()->compartment());
TypeObject *object = gc::NewGCThing<TypeObject>(cx, gc::FINALIZE_TYPE_OBJECT, sizeof(TypeObject));
TypeObject *object = gc::NewGCThing<TypeObject, ALLOW_GC>(cx, gc::FINALIZE_TYPE_OBJECT, sizeof(TypeObject));
if (!object)
return NULL;
new(object) TypeObject(clasp, proto, clasp == &FunctionClass, unknown);

View File

@ -340,9 +340,9 @@ SetPropertyOperation(JSContext *cx, jsbytecode *pc, HandleValue lval, HandleValu
((obj2 = obj->getProto()) && obj2->lastProperty() == entry->pshape)) {
#ifdef DEBUG
if (entry->isOwnPropertyHit()) {
JS_ASSERT(obj->nativeLookupNoAllocation(shape->propid()) == shape);
JS_ASSERT(obj->nativeLookup(cx, shape->propid()) == shape);
} else {
JS_ASSERT(obj2->nativeLookupNoAllocation(shape->propid()) == shape);
JS_ASSERT(obj2->nativeLookup(cx, shape->propid()) == shape);
JS_ASSERT(entry->isPrototypePropertyHit());
JS_ASSERT(entry->kshape != entry->pshape);
JS_ASSERT(!shape->hasSlot());
@ -409,6 +409,16 @@ FetchName(JSContext *cx, HandleObject obj, HandleObject obj2, HandlePropertyName
return true;
}
inline bool
FetchNameNoGC(JSContext *cx, JSObject *pobj, Shape *shape, MutableHandleValue vp)
{
if (!shape || !pobj->isNative() || !shape->isDataDescriptor() || !shape->hasDefaultGetter())
return false;
vp.set(pobj->nativeGetSlot(shape->slot()));
return true;
}
inline bool
GetIntrinsicOperation(JSContext *cx, JSScript *script, jsbytecode *pc, MutableHandleValue vp)
{
@ -427,8 +437,8 @@ SetIntrinsicOperation(JSContext *cx, JSScript *script, jsbytecode *pc, HandleVal
inline bool
NameOperation(JSContext *cx, jsbytecode *pc, MutableHandleValue vp)
{
RootedObject obj(cx, cx->stack.currentScriptedScopeChain());
RootedPropertyName name(cx, cx->stack.currentScript()->getName(pc));
JSObject *obj = cx->stack.currentScriptedScopeChain();
PropertyName *name = cx->stack.currentScript()->getName(pc);
/*
* Skip along the scope chain to the enclosing global object. This is
@ -442,16 +452,26 @@ NameOperation(JSContext *cx, jsbytecode *pc, MutableHandleValue vp)
if (IsGlobalOp(JSOp(*pc)))
obj = &obj->global();
RootedShape shape(cx);
RootedObject scope(cx), pobj(cx);
if (!LookupName(cx, name, obj, &scope, &pobj, &shape))
Shape *shape = NULL;
JSObject *scope = NULL, *pobj = NULL;
if (LookupNameNoGC(cx, name, obj, &scope, &pobj, &shape)) {
if (FetchNameNoGC(cx, pobj, shape, vp))
return true;
JS_ASSERT(!cx->isExceptionPending());
}
RootedObject objRoot(cx, obj), scopeRoot(cx), pobjRoot(cx);
RootedPropertyName nameRoot(cx, name);
RootedShape shapeRoot(cx);
if (!LookupName(cx, nameRoot, objRoot, &scopeRoot, &pobjRoot, &shapeRoot))
return false;
/* Kludge to allow (typeof foo == "undefined") tests. */
JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]);
if (op2 == JSOP_TYPEOF)
return FetchName<true>(cx, scope, pobj, name, shape, vp);
return FetchName<false>(cx, scope, pobj, name, shape, vp);
return FetchName<true>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp);
return FetchName<false>(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp);
}
inline bool

View File

@ -532,7 +532,7 @@ js::Int32ToString(JSContext *cx, int32_t si)
if (JSFlatString *str = c->dtoaCache.lookup(10, si))
return str;
JSShortString *str = js_NewGCShortString(cx);
JSShortString *str = js_NewGCShortString<ALLOW_GC>(cx);
if (!str)
return NULL;
@ -1287,7 +1287,7 @@ js::IndexToString(JSContext *cx, uint32_t index)
if (JSFlatString *str = c->dtoaCache.lookup(10, index))
return str;
JSShortString *str = js_NewGCShortString(cx);
JSShortString *str = js_NewGCShortString<ALLOW_GC>(cx);
if (!str)
return NULL;

View File

@ -3184,7 +3184,7 @@ js::DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, HandleVal
* - Otherwise no property was resolved. Set *propp = NULL and *recursedp = false
* and return true.
*/
static JSBool
static JS_ALWAYS_INLINE JSBool
CallResolveOp(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
MutableHandleObject objp, MutableHandleShape propp, bool *recursedp)
{
@ -3242,7 +3242,7 @@ CallResolveOp(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
}
if (JSID_IS_INT(id) && objp->containsDenseElement(JSID_TO_INT(id))) {
MarkDenseElementFound(propp);
MarkDenseElementFound<ALLOW_GC>(propp);
return true;
}
@ -3255,20 +3255,27 @@ CallResolveOp(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
return true;
}
template <AllowGC allowGC>
static JS_ALWAYS_INLINE bool
LookupPropertyWithFlagsInline(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
MutableHandleObject objp, MutableHandleShape propp)
LookupPropertyWithFlagsInline(JSContext *cx,
typename MaybeRooted<JSObject*, allowGC>::HandleType obj,
typename MaybeRooted<jsid, allowGC>::HandleType id,
unsigned flags,
typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
{
AssertCanGC();
if (allowGC)
AssertCanGC();
/* Search scopes starting with obj and following the prototype link. */
RootedObject current(cx, obj);
typename MaybeRooted<JSObject*, allowGC>::RootType current(cx, obj);
while (true) {
/* Search for a native dense element or property. */
{
if (JSID_IS_INT(id) && current->containsDenseElement(JSID_TO_INT(id))) {
objp.set(current);
MarkDenseElementFound(propp);
MarkDenseElementFound<allowGC>(propp);
return true;
}
@ -3282,9 +3289,20 @@ LookupPropertyWithFlagsInline(JSContext *cx, HandleObject obj, HandleId id, unsi
/* Try obj's class resolve hook if id was not found in obj's scope. */
if (current->getClass()->resolve != JS_ResolveStub) {
bool recursed;
if (!CallResolveOp(cx, current, id, flags, objp, propp, &recursed))
if (!allowGC)
return false;
bool recursed;
if (!CallResolveOp(cx,
MaybeRooted<JSObject*, allowGC>::toHandle(current),
MaybeRooted<jsid, allowGC>::toHandle(id),
flags,
MaybeRooted<JSObject*, allowGC>::toMutableHandle(objp),
MaybeRooted<Shape*, allowGC>::toMutableHandle(propp),
&recursed))
{
return false;
}
if (recursed)
break;
if (propp) {
@ -3296,15 +3314,18 @@ LookupPropertyWithFlagsInline(JSContext *cx, HandleObject obj, HandleId id, unsi
}
}
RootedObject proto(cx);
if (!JSObject::getProto(cx, current, &proto))
return false;
typename MaybeRooted<JSObject*, allowGC>::RootType proto(cx, current->getProto());
if (!proto)
break;
if (!proto->isNative()) {
if (!JSObject::lookupGeneric(cx, proto, id, objp, propp))
if (!allowGC)
return false;
return true;
return JSObject::lookupGeneric(cx,
MaybeRooted<JSObject*, allowGC>::toHandle(proto),
MaybeRooted<jsid, allowGC>::toHandle(id),
MaybeRooted<JSObject*, allowGC>::toMutableHandle(objp),
MaybeRooted<Shape*, allowGC>::toMutableHandle(propp));
}
current = proto;
@ -3319,7 +3340,7 @@ JS_FRIEND_API(JSBool)
baseops::LookupProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp,
MutableHandleShape propp)
{
return LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, objp, propp);
return LookupPropertyWithFlagsInline<ALLOW_GC>(cx, obj, id, cx->resolveFlags, objp, propp);
}
JS_FRIEND_API(JSBool)
@ -3330,14 +3351,14 @@ baseops::LookupElement(JSContext *cx, HandleObject obj, uint32_t index,
if (!IndexToId(cx, index, &id))
return false;
return LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, objp, propp);
return LookupPropertyWithFlagsInline<ALLOW_GC>(cx, obj, id, cx->resolveFlags, objp, propp);
}
bool
js::LookupPropertyWithFlags(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
MutableHandleObject objp, MutableHandleShape propp)
{
return LookupPropertyWithFlagsInline(cx, obj, id, flags, objp, propp);
return LookupPropertyWithFlagsInline<ALLOW_GC>(cx, obj, id, flags, objp, propp);
}
bool
@ -3361,6 +3382,32 @@ js::LookupName(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
return true;
}
bool
js::LookupNameNoGC(JSContext *cx, PropertyName *name, JSObject *scopeChain,
JSObject **objp, JSObject **pobjp, Shape **propp)
{
AutoAssertNoGC nogc;
JS_ASSERT(!*objp && !*pobjp && !*propp);
for (JSObject *scope = scopeChain; scope; scope = scope->enclosingScope()) {
if (scope->getOps()->lookupGeneric)
return false;
if (!LookupPropertyWithFlagsInline<DONT_ALLOW_GC>(cx, scope, NameToId(name),
cx->resolveFlags, pobjp, propp))
{
JS_ASSERT(!cx->isExceptionPending());
return false;
}
if (*propp) {
*objp = scope;
return true;
}
}
return true;
}
bool
js::LookupNameWithGlobalDefault(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
MutableHandleObject objp)
@ -3481,7 +3528,7 @@ js_GetPropertyHelperInline(JSContext *cx, HandleObject obj, HandleObject receive
/* This call site is hot -- use the always-inlined variant of LookupPropertyWithFlags(). */
RootedObject obj2(cx);
RootedShape shape(cx);
if (!LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, &obj2, &shape))
if (!LookupPropertyWithFlagsInline<ALLOW_GC>(cx, obj, id, cx->resolveFlags, &obj2, &shape))
return false;
if (!shape) {
@ -4116,8 +4163,10 @@ baseops::DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
}
bool
js::HasDataProperty(JSContext *cx, HandleObject obj, HandleId id, Value *vp)
js::HasDataProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
AutoAssertNoGC nogc;
if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
*vp = obj->getDenseElement(JSID_TO_INT(id));
return true;

View File

@ -1272,6 +1272,10 @@ extern bool
LookupName(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
MutableHandleObject objp, MutableHandleObject pobjp, MutableHandleShape propp);
extern bool
LookupNameNoGC(JSContext *cx, PropertyName *name, JSObject *scopeChain,
JSObject **objp, JSObject **pobjp, Shape **propp);
/*
* Like LookupName except returns the global object if 'name' is not found in
* any preceding non-global scope.
@ -1341,13 +1345,12 @@ GetMethod(JSContext *cx, HandleObject obj, PropertyName *name, unsigned getHow,
* store the property value in *vp.
*/
extern bool
HasDataProperty(JSContext *cx, HandleObject obj, HandleId id, Value *vp);
HasDataProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp);
inline bool
HasDataProperty(JSContext *cx, HandleObject obj, PropertyName *name, Value *vp)
HasDataProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp)
{
RootedId id(cx, NameToId(name));
return HasDataProperty(cx, obj, id, vp);
return HasDataProperty(cx, obj, NameToId(name), vp);
}
extern JSBool

View File

@ -969,7 +969,7 @@ JSObject::create(JSContext *cx, js::gc::AllocKind kind,
JS_ASSERT(js::gc::GetGCKindSlots(kind, type->clasp) == shape->numFixedSlots());
JS_ASSERT(cx->compartment == type->compartment());
JSObject *obj = js_NewGCObject(cx, kind);
JSObject *obj = js_NewGCObject<js::ALLOW_GC>(cx, kind);
if (!obj)
return NULL;
@ -1014,7 +1014,7 @@ JSObject::createArray(JSContext *cx, js::gc::AllocKind kind,
uint32_t capacity = js::gc::GetGCKindSlots(kind) - js::ObjectElements::VALUES_PER_HEADER;
JSObject *obj = js_NewGCObject(cx, kind);
JSObject *obj = js_NewGCObject<js::ALLOW_GC>(cx, kind);
if (!obj) {
js_ReportOutOfMemory(cx);
return NULL;
@ -1695,7 +1695,7 @@ DefineConstructorAndPrototype(JSContext *cx, Handle<GlobalObject*> global,
JS_ASSERT(proto);
RootedId id(cx, NameToId(ClassName(key, cx)));
JS_ASSERT(!global->nativeLookupNoAllocation(id));
JS_ASSERT(!global->nativeLookup(cx, id));
/* Set these first in case AddTypePropertyId looks for this class. */
global->setSlot(key, ObjectValue(*ctor));

View File

@ -172,7 +172,7 @@ PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject
if (pobj->lastProperty() == entry->pshape) {
#ifdef DEBUG
Rooted<PropertyName*> name(cx, GetNameFromBytecode(cx, script, pc, op));
JS_ASSERT(pobj->nativeContainsNoAllocation(name));
JS_ASSERT(pobj->nativeContains(cx, name));
#endif
*pobjp = pobj;
return NULL;

View File

@ -75,20 +75,20 @@ ShapeTable::init(JSRuntime *rt, UnrootedShape lastProp)
return true;
}
/* static */ bool
Shape::makeOwnBaseShape(JSContext *cx, HandleShape shape)
bool
Shape::makeOwnBaseShape(JSContext *cx)
{
JS_ASSERT(!shape->base()->isOwned());
assertSameCompartmentDebugOnly(cx, shape->compartment());
JS_ASSERT(!base()->isOwned());
assertSameCompartmentDebugOnly(cx, compartment());
UnrootedBaseShape nbase = js_NewGCBaseShape(cx);
UnrootedBaseShape nbase = js_NewGCBaseShape<DONT_ALLOW_GC>(cx);
if (!nbase)
return false;
new (nbase) BaseShape(StackBaseShape(shape));
nbase->setOwned(shape->base()->toUnowned());
new (nbase) BaseShape(StackBaseShape(this));
nbase->setOwned(base()->toUnowned());
shape->base_ = nbase;
this->base_ = nbase;
return true;
}
@ -115,9 +115,9 @@ Shape::handoffTableTo(UnrootedShape shape)
}
/* static */ bool
Shape::hashify(JSContext *cx, HandleShape shape)
Shape::hashify(JSContext *cx, Shape *shape)
{
AssertCanGC();
AutoAssertNoGC nogc;
JS_ASSERT(!shape->hasTable());
if (!shape->ensureOwnBaseShape(cx))
@ -738,7 +738,7 @@ JSObject::putProperty(JSContext *cx, HandleObject obj, HandleId id,
JSObject::changeProperty(JSContext *cx, HandleObject obj, RawShape shape, unsigned attrs, unsigned mask,
PropertyOp getter, StrictPropertyOp setter)
{
JS_ASSERT(obj->nativeContainsNoAllocation(*shape));
JS_ASSERT(obj->nativeContains(cx, shape));
attrs |= shape->attrs & mask;
@ -857,7 +857,7 @@ JSObject::removeProperty(JSContext *cx, jsid id_)
*/
UnrootedShape aprop = self->lastProperty();
for (int n = 50; --n >= 0 && aprop->parent; aprop = aprop->parent)
JS_ASSERT_IF(aprop != shape, self->nativeContainsNoAllocation(*aprop));
JS_ASSERT_IF(aprop != shape, self->nativeContains(cx, aprop));
#endif
}
@ -935,7 +935,7 @@ JSObject::replaceWithNewEquivalentShape(JSContext *cx, Shape *oldShape, Shape *n
JS_ASSERT(cx->compartment == oldShape->compartment());
JS_ASSERT_IF(oldShape != lastProperty(),
inDictionaryMode() &&
nativeLookupNoAllocation(oldShape->propidRef()) == oldShape);
nativeLookup(cx, oldShape->propidRef()) == oldShape);
JSObject *self = this;
@ -1140,7 +1140,7 @@ BaseShape::getUnowned(JSContext *cx, const StackBaseShape &base)
StackBaseShape::AutoRooter root(cx, &base);
UnrootedBaseShape nbase_ = js_NewGCBaseShape(cx);
UnrootedBaseShape nbase_ = js_NewGCBaseShape<ALLOW_GC>(cx);
if (!nbase_)
return NULL;

View File

@ -498,8 +498,6 @@ class Shape : public js::gc::Cell
static inline UnrootedShape search(JSContext *cx, Shape *start, jsid id,
Shape ***pspp, bool adding = false);
static inline UnrootedShape searchNoAllocation(UnrootedShape start, jsid id);
inline void removeFromDictionary(JSObject *obj);
inline void insertIntoDictionary(HeapPtrShape *dictp);
@ -512,7 +510,7 @@ class Shape : public js::gc::Cell
static UnrootedShape replaceLastProperty(JSContext *cx, const StackBaseShape &base,
TaggedProto proto, HandleShape shape);
static bool hashify(JSContext *cx, HandleShape shape);
static bool hashify(JSContext *cx, Shape *shape);
void handoffTableTo(UnrootedShape newShape);
inline void setParent(UnrootedShape p);
@ -520,11 +518,10 @@ class Shape : public js::gc::Cell
bool ensureOwnBaseShape(JSContext *cx) {
if (base()->isOwned())
return true;
RootedShape self(cx, this);
return makeOwnBaseShape(cx, self);
return makeOwnBaseShape(cx);
}
static bool makeOwnBaseShape(JSContext *cx, HandleShape shape);
bool makeOwnBaseShape(JSContext *cx);
public:
bool hasTable() const { return base()->hasTable(); }
@ -1055,14 +1052,7 @@ namespace js {
inline UnrootedShape
Shape::search(JSContext *cx, Shape *start, jsid id, Shape ***pspp, bool adding)
{
AssertCanGC();
#ifdef DEBUG
{
SkipRoot skip0(cx, &start);
SkipRoot skip1(cx, &id);
MaybeCheckStackRoots(cx);
}
#endif
AutoAssertNoGC nogc;
if (start->inDictionary()) {
*pspp = start->table().search(id, adding);
@ -1078,14 +1068,10 @@ Shape::search(JSContext *cx, Shape *start, jsid id, Shape ***pspp, bool adding)
if (start->numLinearSearches() == LINEAR_SEARCHES_MAX) {
if (start->isBigEnoughForAShapeTable()) {
RootedShape startRoot(cx, start);
RootedId idRoot(cx, id);
if (Shape::hashify(cx, startRoot)) {
Shape **spp = startRoot->table().search(idRoot, adding);
if (Shape::hashify(cx, start)) {
Shape **spp = start->table().search(id, adding);
return SHAPE_FETCH(spp);
}
start = startRoot;
id = idRoot;
}
/*
* No table built -- there weren't enough entries, or OOM occurred.
@ -1104,22 +1090,6 @@ Shape::search(JSContext *cx, Shape *start, jsid id, Shape ***pspp, bool adding)
return UnrootedShape(NULL);
}
/* static */ inline UnrootedShape
Shape::searchNoAllocation(UnrootedShape start, jsid id)
{
if (start->hasTable()) {
Shape **spp = start->table().search(id, false);
return SHAPE_FETCH(spp);
}
for (UnrootedShape shape = start; shape; shape = shape->parent) {
if (shape->propidRef() == id)
return shape;
}
return UnrootedShape(NULL);
}
template<> struct RootKind<Shape *> : SpecificRootKind<Shape *, THING_ROOT_SHAPE> {};
template<> struct RootKind<BaseShape *> : SpecificRootKind<BaseShape *, THING_ROOT_BASE_SHAPE> {};

View File

@ -507,8 +507,9 @@ MarkNonNativePropertyFound(MutableHandleShape propp)
propp.set(reinterpret_cast<Shape*>(1));
}
template <AllowGC allowGC>
static inline void
MarkDenseElementFound(MutableHandleShape propp)
MarkDenseElementFound(typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
{
propp.set(reinterpret_cast<Shape*>(1));
}

View File

@ -1990,8 +1990,7 @@ InterpretDollar(RegExpStatics *res, const jschar *dp, const jschar *ep,
static bool
FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t *sizep)
{
RootedObject base(cx, rdata.elembase);
if (base) {
if (rdata.elembase) {
/*
* The base object is used when replace was passed a lambda which looks like
* 'function(a) { return b[a]; }' for the base object b. b will not change
@ -1999,8 +1998,8 @@ FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t
* to accessing a scripted getter or a value with a scripted toString.
*/
JS_ASSERT(rdata.lambda);
JS_ASSERT(!base->getOps()->lookupProperty);
JS_ASSERT(!base->getOps()->getProperty);
JS_ASSERT(!rdata.elembase->getOps()->lookupProperty);
JS_ASSERT(!rdata.elembase->getOps()->getProperty);
Value match;
if (!res->createLastMatch(cx, &match))
@ -2017,8 +2016,7 @@ FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t
}
Value v;
RootedId id(cx, AtomToId(atom));
if (HasDataProperty(cx, base, id, &v) && v.isString()) {
if (HasDataProperty(cx, rdata.elembase, AtomToId(atom), &v) && v.isString()) {
rdata.repstr = v.toString()->ensureLinear(cx);
if (!rdata.repstr)
return false;

View File

@ -1305,7 +1305,7 @@ class GetPropCompiler : public PICStubCompiler
// that will complicate property lookups on them.
JS_ASSERT_IF(expando, expando->isNative() && expando->getProto() == NULL);
if (expando && expando->nativeLookupNoAllocation(name) == NULL) {
if (expando && expando->nativeLookup(cx, name) == NULL) {
Jump expandoGuard = masm.testObject(Assembler::NotEqual, expandoAddress);
if (!shapeMismatches.append(expandoGuard))
return error();

View File

@ -43,63 +43,31 @@ Debug_SetSlotRangeToCrashOnTouch(HeapSlot *begin, HeapSlot *end)
inline js::UnrootedShape
js::ObjectImpl::nativeLookup(JSContext *cx, PropertyId pid)
{
RootedId id(cx, pid.asId());
return nativeLookup(cx, id);
return nativeLookup(cx, pid.asId());
}
inline js::UnrootedShape
js::ObjectImpl::nativeLookup(JSContext *cx, PropertyName *name)
{
return nativeLookup(cx, PropertyId(name));
}
inline js::UnrootedShape
js::ObjectImpl::nativeLookupNoAllocation(PropertyId pid)
{
return nativeLookupNoAllocation(pid.asId());
}
inline js::UnrootedShape
js::ObjectImpl::nativeLookupNoAllocation(PropertyName *name)
{
return nativeLookupNoAllocation(PropertyId(name));
return nativeLookup(cx, NameToId(name));
}
inline bool
js::ObjectImpl::nativeContains(JSContext *cx, JS::Handle<jsid> id)
js::ObjectImpl::nativeContains(JSContext *cx, jsid id)
{
return nativeLookup(cx, id) != NULL;
}
inline bool
js::ObjectImpl::nativeContains(JSContext *cx, JS::Handle<PropertyName*> name)
js::ObjectImpl::nativeContains(JSContext *cx, PropertyName *name)
{
return nativeLookup(cx, name) != NULL;
}
inline bool
js::ObjectImpl::nativeContains(JSContext *cx, JS::Handle<Shape*> shape)
js::ObjectImpl::nativeContains(JSContext *cx, Shape *shape)
{
RootedId id(cx, shape->propid());
return nativeLookup(cx, id) == shape;
}
inline bool
js::ObjectImpl::nativeContainsNoAllocation(jsid id)
{
return nativeLookupNoAllocation(id) != NULL;
}
inline bool
js::ObjectImpl::nativeContainsNoAllocation(PropertyName *name)
{
return nativeLookupNoAllocation(name) != NULL;
}
inline bool
js::ObjectImpl::nativeContainsNoAllocation(Shape &shape)
{
return nativeLookupNoAllocation(shape.propid()) == &shape;
return nativeLookup(cx, shape->propid()) == shape;
}
inline bool

View File

@ -264,21 +264,14 @@ js::ObjectImpl::slotInRange(uint32_t slot, SentinelAllowed sentinel) const
MOZ_NEVER_INLINE
#endif
UnrootedShape
js::ObjectImpl::nativeLookup(JSContext *cx, HandleId id)
js::ObjectImpl::nativeLookup(JSContext *cx, jsid id)
{
AssertCanGC();
AutoAssertNoGC nogc;
MOZ_ASSERT(isNative());
Shape **spp;
return Shape::search(cx, lastProperty(), id, &spp);
}
UnrootedShape
js::ObjectImpl::nativeLookupNoAllocation(jsid id)
{
MOZ_ASSERT(isNative());
return Shape::searchNoAllocation(lastProperty(), id);
}
void
js::ObjectImpl::markChildren(JSTracer *trc)
{

View File

@ -1209,21 +1209,13 @@ class ObjectImpl : public gc::Cell
/* Compute dynamicSlotsCount() for this object. */
inline uint32_t numDynamicSlots() const;
UnrootedShape nativeLookup(JSContext *cx, HandleId id);
UnrootedShape nativeLookup(JSContext *cx, jsid id);
inline UnrootedShape nativeLookup(JSContext *cx, PropertyId pid);
inline UnrootedShape nativeLookup(JSContext *cx, PropertyName *name);
UnrootedShape nativeLookupNoAllocation(jsid id);
inline UnrootedShape nativeLookupNoAllocation(PropertyId pid);
inline UnrootedShape nativeLookupNoAllocation(PropertyName *name);
inline bool nativeContains(JSContext *cx, Handle<jsid> id);
inline bool nativeContains(JSContext *cx, Handle<PropertyName*> name);
inline bool nativeContains(JSContext *cx, Handle<Shape*> shape);
inline bool nativeContainsNoAllocation(jsid id);
inline bool nativeContainsNoAllocation(PropertyName *name);
inline bool nativeContainsNoAllocation(Shape &shape);
inline bool nativeContains(JSContext *cx, jsid id);
inline bool nativeContains(JSContext *cx, PropertyName* name);
inline bool nativeContains(JSContext *cx, Shape* shape);
inline JSClass *getJSClass() const;
inline bool hasClass(const Class *c) const;

View File

@ -331,17 +331,17 @@ RegExpObject::init(JSContext *cx, HandleAtom source, RegExpFlag flags)
JS_ASSERT(!self->nativeEmpty());
}
JS_ASSERT(self->nativeLookupNoAllocation(NameToId(cx->names().lastIndex))->slot() ==
JS_ASSERT(self->nativeLookup(cx, NameToId(cx->names().lastIndex))->slot() ==
LAST_INDEX_SLOT);
JS_ASSERT(self->nativeLookupNoAllocation(NameToId(cx->names().source))->slot() ==
JS_ASSERT(self->nativeLookup(cx, NameToId(cx->names().source))->slot() ==
SOURCE_SLOT);
JS_ASSERT(self->nativeLookupNoAllocation(NameToId(cx->names().global))->slot() ==
JS_ASSERT(self->nativeLookup(cx, NameToId(cx->names().global))->slot() ==
GLOBAL_FLAG_SLOT);
JS_ASSERT(self->nativeLookupNoAllocation(NameToId(cx->names().ignoreCase))->slot() ==
JS_ASSERT(self->nativeLookup(cx, NameToId(cx->names().ignoreCase))->slot() ==
IGNORE_CASE_FLAG_SLOT);
JS_ASSERT(self->nativeLookupNoAllocation(NameToId(cx->names().multiline))->slot() ==
JS_ASSERT(self->nativeLookup(cx, NameToId(cx->names().multiline))->slot() ==
MULTILINE_FLAG_SLOT);
JS_ASSERT(self->nativeLookupNoAllocation(NameToId(cx->names().sticky))->slot() ==
JS_ASSERT(self->nativeLookup(cx, NameToId(cx->names().sticky))->slot() ==
STICKY_FLAG_SLOT);
/*

View File

@ -27,8 +27,8 @@ NewShortString(JSContext *cx, Latin1Chars chars)
size_t len = chars.length();
JS_ASSERT(JSShortString::lengthFits(len));
UnrootedInlineString str = JSInlineString::lengthFits(len)
? JSInlineString::new_(cx)
: JSShortString::new_(cx);
? JSInlineString::new_<ALLOW_GC>(cx)
: JSShortString::new_<ALLOW_GC>(cx);
if (!str)
return NULL;
@ -51,8 +51,8 @@ NewShortString(JSContext *cx, StableTwoByteChars chars)
*/
JS_ASSERT(JSShortString::lengthFits(len));
JSInlineString *str = JSInlineString::lengthFits(len)
? JSInlineString::new_(cx)
: JSShortString::new_(cx);
? JSInlineString::new_<ALLOW_GC>(cx)
: JSShortString::new_<ALLOW_GC>(cx);
if (!str)
return NULL;
@ -74,8 +74,8 @@ NewShortString(JSContext *cx, TwoByteChars chars)
*/
JS_ASSERT(JSShortString::lengthFits(len));
JSInlineString *str = JSInlineString::lengthFits(len)
? JSInlineString::tryNew_(cx)
: JSShortString::tryNew_(cx);
? JSInlineString::new_<DONT_ALLOW_GC>(cx)
: JSShortString::new_<DONT_ALLOW_GC>(cx);
if (!str) {
jschar tmp[JSShortString::MAX_SHORT_LENGTH];
PodCopy(tmp, chars.start().get(), len);
@ -186,7 +186,7 @@ JSRope::newStringMaybeAllowGC(JSContext *cx,
{
if (!validateLength(cx, length))
return NULL;
JSRope *str = (JSRope *) (allowGC ? js_NewGCString(cx) : js_TryNewGCString(cx));
JSRope *str = (JSRope *) js_NewGCString<allowGC>(cx);
if (!str)
return NULL;
str->init(left, right, length);
@ -243,7 +243,7 @@ JSDependentString::new_(JSContext *cx, JSLinearString *baseArg, const jschar *ch
if (JSShortString::lengthFits(length))
return js::NewShortString(cx, js::TwoByteChars(chars, length));
JSDependentString *str = (JSDependentString *)js_NewGCString(cx);
JSDependentString *str = (JSDependentString *)js_NewGCString<js::ALLOW_GC>(cx);
if (!str)
return NULL;
str->init(base, chars, length);
@ -293,23 +293,18 @@ JSStableString::new_(JSContext *cx, const jschar *chars, size_t length)
if (!validateLength(cx, length))
return NULL;
JSStableString *str = (JSStableString *)js_NewGCString(cx);
JSStableString *str = (JSStableString *)js_NewGCString<js::ALLOW_GC>(cx);
if (!str)
return NULL;
str->init(chars, length);
return str;
}
template <js::AllowGC allowGC>
JS_ALWAYS_INLINE JSInlineString *
JSInlineString::new_(JSContext *cx)
{
return (JSInlineString *)js_NewGCString(cx);
}
JS_ALWAYS_INLINE JSInlineString *
JSInlineString::tryNew_(JSContext *cx)
{
return (JSInlineString *)js_TryNewGCString(cx);
return (JSInlineString *)js_NewGCString<allowGC>(cx);
}
JS_ALWAYS_INLINE jschar *
@ -328,16 +323,11 @@ JSInlineString::resetLength(size_t length)
JS_ASSERT(lengthFits(length) || (isShort() && JSShortString::lengthFits(length)));
}
template <js::AllowGC allowGC>
JS_ALWAYS_INLINE JSShortString *
JSShortString::new_(JSContext *cx)
{
return js_NewGCShortString(cx);
}
JS_ALWAYS_INLINE JSShortString *
JSShortString::tryNew_(JSContext *cx)
{
return js_TryNewGCShortString(cx);
return js_NewGCShortString<allowGC>(cx);
}
JS_ALWAYS_INLINE void

View File

@ -319,7 +319,7 @@ ConcatStringsMaybeAllowGC(JSContext *cx,
return NULL;
if (JSShortString::lengthFits(wholeLength)) {
JSShortString *str = allowGC ? js_NewGCShortString(cx) : js_TryNewGCShortString(cx);
JSShortString *str = js_NewGCShortString<allowGC>(cx);
if (!str)
return NULL;
const jschar *leftChars = left->getChars(cx);

View File

@ -656,8 +656,8 @@ class JSInlineString : public JSFlatString
static const size_t MAX_INLINE_LENGTH = NUM_INLINE_CHARS - 1;
public:
template <js::AllowGC allowGC>
static inline JSInlineString *new_(JSContext *cx);
static inline JSInlineString *tryNew_(JSContext *cx);
inline jschar *init(size_t length);
@ -688,8 +688,8 @@ class JSShortString : public JSInlineString
jschar inlineStorageExtension[INLINE_EXTENSION_CHARS];
public:
template <js::AllowGC allowGC>
static inline JSShortString *new_(JSContext *cx);
static inline JSShortString *tryNew_(JSContext *cx);
static const size_t MAX_SHORT_LENGTH = JSString::NUM_INLINE_CHARS +
INLINE_EXTENSION_CHARS

View File

@ -40,7 +40,7 @@ StringObject::init(JSContext *cx, HandleString str)
}
}
JS_ASSERT(self->nativeLookupNoAllocation(NameToId(cx->names().length))->slot() == LENGTH_SLOT);
JS_ASSERT(self->nativeLookup(cx, NameToId(cx->names().length))->slot() == LENGTH_SLOT);
self->setStringThis(str);