bool ScopedThreadSafeStringInspector::ensureChars(ThreadSafeContext *cx, const AutoCheckCannotGC &nogc) { if (state_ != Uninitialized) return true; if (cx->isExclusiveContext()) { JSLinearString *linear = str_->ensureLinear(cx->asExclusiveContext()); if (!linear) return false; if (linear->hasTwoByteChars()) { state_ = TwoByte; twoByteChars_ = linear->twoByteChars(nogc); } else { state_ = Latin1; latin1Chars_ = linear->latin1Chars(nogc); } } else { if (str_->isLinear()) { if (str_->hasLatin1Chars()) { state_ = Latin1; latin1Chars_ = str_->asLinear().latin1Chars(nogc); } else { state_ = TwoByte; twoByteChars_ = str_->asLinear().twoByteChars(nogc); } } else { if (str_->hasLatin1Chars()) { ScopedJSFreePtr<Latin1Char> chars; if (!str_->asRope().copyLatin1Chars(cx, chars)) return false; state_ = Latin1; latin1Chars_ = chars; scopedChars_ = chars.forget(); } else { ScopedJSFreePtr<jschar> chars; if (!str_->asRope().copyTwoByteChars(cx, chars)) return false; state_ = TwoByte; twoByteChars_ = chars; scopedChars_ = chars.forget(); } } } MOZ_ASSERT(state_ != Uninitialized); return true; }
static JSString* CopyStringPure(JSContext* cx, JSString* str) { /* * Directly allocate the copy in the destination compartment, rather than * first flattening it (and possibly allocating in source compartment), * because we don't know whether the flattening will pay off later. */ size_t len = str->length(); JSString* copy; if (str->isLinear()) { /* Only use AutoStableStringChars if the NoGC allocation fails. */ if (str->hasLatin1Chars()) { JS::AutoCheckCannotGC nogc; copy = NewStringCopyN<NoGC>(cx, str->asLinear().latin1Chars(nogc), len); } else { JS::AutoCheckCannotGC nogc; copy = NewStringCopyNDontDeflate<NoGC>(cx, str->asLinear().twoByteChars(nogc), len); } if (copy) return copy; AutoStableStringChars chars(cx); if (!chars.init(cx, str)) return nullptr; return chars.isLatin1() ? NewStringCopyN<CanGC>(cx, chars.latin1Range().begin().get(), len) : NewStringCopyNDontDeflate<CanGC>(cx, chars.twoByteRange().begin().get(), len); } if (str->hasLatin1Chars()) { ScopedJSFreePtr<Latin1Char> copiedChars; if (!str->asRope().copyLatin1CharsZ(cx, copiedChars)) return nullptr; return NewString<CanGC>(cx, copiedChars.forget(), len); } ScopedJSFreePtr<char16_t> copiedChars; if (!str->asRope().copyTwoByteCharsZ(cx, copiedChars)) return nullptr; return NewStringDontDeflate<CanGC>(cx, copiedChars.forget(), len); }
bool JSCompartment::wrap(JSContext *cx, JSString **strp) { JS_ASSERT(!cx->runtime()->isAtomsCompartment(this)); JS_ASSERT(cx->compartment() == this); /* If the string is already in this compartment, we are done. */ JSString *str = *strp; if (str->zone() == zone()) return true; /* If the string is an atom, we don't have to copy. */ if (str->isAtom()) { JS_ASSERT(cx->runtime()->isAtomsZone(str->zone())); return true; } /* Check the cache. */ RootedValue key(cx, StringValue(str)); if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(key)) { *strp = p->value().get().toString(); return true; } /* * No dice. Make a copy, and cache it. Directly allocate the copy in the * destination compartment, rather than first flattening it (and possibly * allocating in source compartment), because we don't know whether the * flattening will pay off later. */ JSString *copy; if (str->hasPureChars()) { copy = js_NewStringCopyN<CanGC>(cx, str->pureChars(), str->length()); } else { ScopedJSFreePtr<jschar> copiedChars; if (!str->copyNonPureCharsZ(cx, copiedChars)) return false; copy = js_NewString<CanGC>(cx, copiedChars.forget(), str->length()); } if (!copy) return false; if (!putWrapper(cx, key, StringValue(copy))) return false; *strp = copy; return true; }