Mypal/js/xpconnect/src/XPCString.cpp
2021-02-04 16:48:36 +02:00

143 lines
4.3 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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