diff options
Diffstat (limited to 'js/xpconnect/src/XPCString.cpp')
-rw-r--r-- | js/xpconnect/src/XPCString.cpp | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/js/xpconnect/src/XPCString.cpp b/js/xpconnect/src/XPCString.cpp new file mode 100644 index 000000000..42a57744e --- /dev/null +++ b/js/xpconnect/src/XPCString.cpp @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set ts=8 sts=4 et sw=4 tw=99: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Infrastructure for sharing DOMString data with JSStrings. + * + * Importing an nsAString into JS: + * If possible (GetSharedBufferHandle works) use the external string support in + * JS to create a JSString that points to the readable's buffer. We keep a + * reference to the buffer handle until the JSString is finalized. + * + * Exporting a JSString as an nsAReadable: + * Wrap the JSString with a root-holding XPCJSReadableStringWrapper, which roots + * the string and exposes its buffer via the nsAString interface, as + * well as providing refcounting support. + */ + +#include "nsAutoPtr.h" +#include "nscore.h" +#include "nsString.h" +#include "nsStringBuffer.h" +#include "jsapi.h" +#include "xpcpublic.h" + +using namespace JS; + +// static +void +XPCStringConvert::FreeZoneCache(JS::Zone* zone) +{ + // Put the zone user data into an AutoPtr (which will do the cleanup for us), + // and null out the user data (which may already be null). + nsAutoPtr<ZoneStringCache> cache(static_cast<ZoneStringCache*>(JS_GetZoneUserData(zone))); + JS_SetZoneUserData(zone, nullptr); +} + +// static +void +XPCStringConvert::ClearZoneCache(JS::Zone* zone) +{ + // Although we clear the cache in FinalizeDOMString if needed, we also clear + // the cache here to avoid a dangling JSString* pointer when compacting GC + // moves the external string in memory. + + ZoneStringCache* cache = static_cast<ZoneStringCache*>(JS_GetZoneUserData(zone)); + if (cache) { + cache->mBuffer = nullptr; + cache->mLength = 0; + cache->mString = nullptr; + } +} + +// static +void +XPCStringConvert::FinalizeLiteral(JS::Zone* zone, const JSStringFinalizer* fin, char16_t* chars) +{ +} + +const JSStringFinalizer XPCStringConvert::sLiteralFinalizer = + { XPCStringConvert::FinalizeLiteral }; + +// static +void +XPCStringConvert::FinalizeDOMString(JS::Zone* zone, const JSStringFinalizer* fin, char16_t* chars) +{ + nsStringBuffer* buf = nsStringBuffer::FromData(chars); + + // Clear the ZoneStringCache if needed, as this can be called outside GC + // when flattening an external string. + ZoneStringCache* cache = static_cast<ZoneStringCache*>(JS_GetZoneUserData(zone)); + if (cache && cache->mBuffer == buf) { + cache->mBuffer = nullptr; + cache->mLength = 0; + cache->mString = nullptr; + } + + buf->Release(); +} + +const JSStringFinalizer XPCStringConvert::sDOMStringFinalizer = + { XPCStringConvert::FinalizeDOMString }; + +// convert a readable to a JSString, copying string data +// static +bool +XPCStringConvert::ReadableToJSVal(JSContext* cx, + const nsAString& readable, + nsStringBuffer** sharedBuffer, + MutableHandleValue vp) +{ + *sharedBuffer = nullptr; + + uint32_t length = readable.Length(); + + if (readable.IsLiteral()) { + JSString* str = JS_NewExternalString(cx, + static_cast<const char16_t*>(readable.BeginReading()), + length, &sLiteralFinalizer); + if (!str) + return false; + vp.setString(str); + return true; + } + + nsStringBuffer* buf = nsStringBuffer::FromString(readable); + if (buf) { + bool shared; + if (!StringBufferToJSVal(cx, buf, length, vp, &shared)) + return false; + if (shared) + *sharedBuffer = buf; + return true; + } + + // blech, have to copy. + JSString* str = JS_NewUCStringCopyN(cx, readable.BeginReading(), length); + if (!str) + return false; + vp.setString(str); + return true; +} + +namespace xpc { + +bool +NonVoidStringToJsval(JSContext* cx, nsAString& str, MutableHandleValue rval) +{ + nsStringBuffer* sharedBuffer; + if (!XPCStringConvert::ReadableToJSVal(cx, str, &sharedBuffer, rval)) + return false; + + if (sharedBuffer) { + // The string was shared but ReadableToJSVal didn't addref it. + // Move the ownership from str to jsstr. + str.ForgetSharedBuffer(); + } + return true; +} + +} // namespace xpc |