mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-09-26 23:54:56 +00:00
171 lines
4.5 KiB
C++
171 lines
4.5 KiB
C++
/* -*- 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/. */
|
|
|
|
#include "vm/StringBuffer.h"
|
|
|
|
#include "mozilla/Range.h"
|
|
|
|
#include "jsobjinlines.h"
|
|
|
|
#include "vm/String-inl.h"
|
|
|
|
using namespace js;
|
|
|
|
template <typename CharT, class Buffer>
|
|
static CharT*
|
|
ExtractWellSized(ExclusiveContext* cx, Buffer& cb)
|
|
{
|
|
size_t capacity = cb.capacity();
|
|
size_t length = cb.length();
|
|
|
|
CharT* buf = cb.extractRawBuffer();
|
|
if (!buf)
|
|
return nullptr;
|
|
|
|
/* For medium/big buffers, avoid wasting more than 1/4 of the memory. */
|
|
MOZ_ASSERT(capacity >= length);
|
|
if (length > Buffer::sMaxInlineStorage && capacity - length > length / 4) {
|
|
CharT* tmp = cx->zone()->pod_realloc<CharT>(buf, capacity, length + 1);
|
|
if (!tmp) {
|
|
js_free(buf);
|
|
ReportOutOfMemory(cx);
|
|
return nullptr;
|
|
}
|
|
buf = tmp;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
char16_t*
|
|
StringBuffer::stealChars()
|
|
{
|
|
if (isLatin1() && !inflateChars())
|
|
return nullptr;
|
|
|
|
return ExtractWellSized<char16_t>(cx, twoByteChars());
|
|
}
|
|
|
|
bool
|
|
StringBuffer::inflateChars()
|
|
{
|
|
MOZ_ASSERT(isLatin1());
|
|
|
|
TwoByteCharBuffer twoByte(cx);
|
|
|
|
/*
|
|
* Note: we don't use Vector::capacity() because it always returns a
|
|
* value >= sInlineCapacity. Since Latin1CharBuffer::sInlineCapacity >
|
|
* TwoByteCharBuffer::sInlineCapacitychars, we'd always malloc here.
|
|
*/
|
|
size_t capacity = Max(reserved_, latin1Chars().length());
|
|
if (!twoByte.reserve(capacity))
|
|
return false;
|
|
|
|
twoByte.infallibleAppend(latin1Chars().begin(), latin1Chars().length());
|
|
|
|
cb.destroy();
|
|
cb.construct<TwoByteCharBuffer>(Move(twoByte));
|
|
return true;
|
|
}
|
|
|
|
template <typename CharT, class Buffer>
|
|
static JSFlatString*
|
|
FinishStringFlat(ExclusiveContext* cx, StringBuffer& sb, Buffer& cb)
|
|
{
|
|
size_t len = sb.length();
|
|
if (!sb.append('\0'))
|
|
return nullptr;
|
|
|
|
ScopedJSFreePtr<CharT> buf(ExtractWellSized<CharT>(cx, cb));
|
|
if (!buf)
|
|
return nullptr;
|
|
|
|
JSFlatString* str = NewStringDontDeflate<CanGC>(cx, buf.get(), len);
|
|
if (!str)
|
|
return nullptr;
|
|
|
|
/*
|
|
* The allocation was made on a TempAllocPolicy, so account for the string
|
|
* data on the string's zone.
|
|
*/
|
|
str->zone()->updateMallocCounter(sizeof(CharT) * len);
|
|
|
|
buf.forget();
|
|
return str;
|
|
}
|
|
|
|
JSFlatString*
|
|
StringBuffer::finishString()
|
|
{
|
|
size_t len = length();
|
|
if (len == 0)
|
|
return cx->names().empty;
|
|
|
|
if (!JSString::validateLength(cx, len))
|
|
return nullptr;
|
|
|
|
JS_STATIC_ASSERT(JSFatInlineString::MAX_LENGTH_TWO_BYTE < TwoByteCharBuffer::InlineLength);
|
|
JS_STATIC_ASSERT(JSFatInlineString::MAX_LENGTH_LATIN1 < Latin1CharBuffer::InlineLength);
|
|
|
|
if (isLatin1()) {
|
|
if (JSInlineString::lengthFits<Latin1Char>(len)) {
|
|
mozilla::Range<const Latin1Char> range(latin1Chars().begin(), len);
|
|
return NewInlineString<CanGC>(cx, range);
|
|
}
|
|
} else {
|
|
if (JSInlineString::lengthFits<char16_t>(len)) {
|
|
mozilla::Range<const char16_t> range(twoByteChars().begin(), len);
|
|
return NewInlineString<CanGC>(cx, range);
|
|
}
|
|
}
|
|
|
|
return isLatin1()
|
|
? FinishStringFlat<Latin1Char>(cx, *this, latin1Chars())
|
|
: FinishStringFlat<char16_t>(cx, *this, twoByteChars());
|
|
}
|
|
|
|
JSAtom*
|
|
StringBuffer::finishAtom()
|
|
{
|
|
size_t len = length();
|
|
if (len == 0)
|
|
return cx->names().empty;
|
|
|
|
if (isLatin1()) {
|
|
JSAtom* atom = AtomizeChars(cx, latin1Chars().begin(), len);
|
|
latin1Chars().clear();
|
|
return atom;
|
|
}
|
|
|
|
JSAtom* atom = AtomizeChars(cx, twoByteChars().begin(), len);
|
|
twoByteChars().clear();
|
|
return atom;
|
|
}
|
|
|
|
bool
|
|
js::ValueToStringBufferSlow(JSContext* cx, const Value& arg, StringBuffer& sb)
|
|
{
|
|
RootedValue v(cx, arg);
|
|
if (!ToPrimitive(cx, JSTYPE_STRING, &v))
|
|
return false;
|
|
|
|
if (v.isString())
|
|
return sb.append(v.toString());
|
|
if (v.isNumber())
|
|
return NumberValueToStringBuffer(cx, v, sb);
|
|
if (v.isBoolean())
|
|
return BooleanToStringBuffer(v.toBoolean(), sb);
|
|
if (v.isNull())
|
|
return sb.append(cx->names().null);
|
|
if (v.isSymbol()) {
|
|
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_SYMBOL_TO_STRING);
|
|
return false;
|
|
}
|
|
MOZ_ASSERT(v.isUndefined());
|
|
return sb.append(cx->names().undefined);
|
|
}
|