mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1645845 - Add ParserAtomsTable, parser atoms types, common parser names table, and base parser atoms implementation. r=mgaudet,tcampbell
Differential Revision: https://phabricator.services.mozilla.com/D79714
This commit is contained in:
parent
24a7deb2a4
commit
b307e7031d
@ -62,6 +62,12 @@ set_define('JS_64BIT', depends(target)(lambda t: t.bitness == 64 or None))
|
||||
set_define('JS_PUNBOX64', depends(target)(lambda t: t.bitness == 64 or None))
|
||||
set_define('JS_NUNBOX32', depends(target)(lambda t: t.bitness == 32 or None))
|
||||
|
||||
# Bits of Stencil-related parser-atoms work are being landed before
|
||||
# being enabled. This define controls that code, and will be removed,
|
||||
# along with guard code in ParserAtoms.cpp, when the final transition
|
||||
# to parser atoms lands.
|
||||
set_define('JS_PARSER_ATOMS', None)
|
||||
|
||||
|
||||
# SpiderMonkey as a shared library, and how its symbols are exported
|
||||
# ==================================================================
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "jstypes.h"
|
||||
#include "mozmemory.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
/* The public JS engine namespace. */
|
||||
namespace JS {}
|
||||
@ -650,6 +651,7 @@ struct FreePolicy {
|
||||
|
||||
typedef mozilla::UniquePtr<char[], JS::FreePolicy> UniqueChars;
|
||||
typedef mozilla::UniquePtr<char16_t[], JS::FreePolicy> UniqueTwoByteChars;
|
||||
typedef mozilla::UniquePtr<JS::Latin1Char[], JS::FreePolicy> UniqueLatin1Chars;
|
||||
|
||||
} // namespace JS
|
||||
|
||||
|
@ -74,6 +74,7 @@ using JS::Latin1CharsZ;
|
||||
using JS::TwoByteChars;
|
||||
using JS::TwoByteCharsZ;
|
||||
using JS::UniqueChars;
|
||||
using JS::UniqueLatin1Chars;
|
||||
using JS::UniqueTwoByteChars;
|
||||
using JS::UTF8Chars;
|
||||
using JS::UTF8CharsZ;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "mozilla/Variant.h"
|
||||
|
||||
#include "ds/LifoAlloc.h"
|
||||
#include "frontend/ParserAtom.h"
|
||||
#include "frontend/SharedContext.h"
|
||||
#include "frontend/Stencil.h"
|
||||
#include "frontend/UsedNameTracker.h"
|
||||
@ -75,6 +76,9 @@ struct MOZ_RAII CompilationInfo : public JS::CustomAutoRooter {
|
||||
// onto them.
|
||||
AutoKeepAtoms keepAtoms;
|
||||
|
||||
// Table of parser atoms for this compilation.
|
||||
ParserAtomsTable parserAtoms;
|
||||
|
||||
Directives directives;
|
||||
|
||||
ScopeContext scopeContext;
|
||||
@ -142,6 +146,7 @@ struct MOZ_RAII CompilationInfo : public JS::CustomAutoRooter {
|
||||
cx(cx),
|
||||
options(options),
|
||||
keepAtoms(cx),
|
||||
parserAtoms(cx),
|
||||
directives(options.forceStrictMode()),
|
||||
scopeContext(enclosingScope, enclosingEnv),
|
||||
script(cx),
|
||||
|
442
js/src/frontend/ParserAtom.cpp
Normal file
442
js/src/frontend/ParserAtom.cpp
Normal file
@ -0,0 +1,442 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||
* 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 "frontend/ParserAtom.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "jsnum.h"
|
||||
|
||||
#include "frontend/NameCollections.h"
|
||||
#include "vm/JSContext.h"
|
||||
#include "vm/Printer.h"
|
||||
#include "vm/Runtime.h"
|
||||
#include "vm/StringType.h"
|
||||
|
||||
//
|
||||
// Parser-Atoms should be disabled for now. This check ensures that.
|
||||
// NOTE: This will be removed when the final transition patches from
|
||||
// JS-atoms to parser-atoms lands.
|
||||
//
|
||||
#ifdef JS_PARSER_ATOMS
|
||||
# error "Parser atoms define should remain disabled until this is removed."
|
||||
#endif
|
||||
|
||||
using namespace js;
|
||||
using namespace js::frontend;
|
||||
|
||||
namespace js {
|
||||
namespace frontend {
|
||||
|
||||
static JS::OOM PARSER_ATOMS_OOM;
|
||||
|
||||
mozilla::GenericErrorResult<OOM&> RaiseParserAtomsOOMError(JSContext* cx) {
|
||||
js::ReportOutOfMemory(cx);
|
||||
return mozilla::Err(PARSER_ATOMS_OOM);
|
||||
}
|
||||
|
||||
bool ParserAtomEntry::equalsJSAtom(JSAtom* other) const {
|
||||
// Compare hashes first.
|
||||
if (hash_ != other->hash()) {
|
||||
return false;
|
||||
}
|
||||
if (length_ != other->length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
|
||||
if (hasTwoByteChars()) {
|
||||
// Compare heap-allocated 16-bit chars to atom.
|
||||
return other->hasLatin1Chars()
|
||||
? EqualChars(twoByteChars(), other->latin1Chars(nogc), length_)
|
||||
: EqualChars(twoByteChars(), other->twoByteChars(nogc), length_);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(hasLatin1Chars());
|
||||
return other->hasLatin1Chars()
|
||||
? EqualChars(latin1Chars(), other->latin1Chars(nogc), length_)
|
||||
: EqualChars(latin1Chars(), other->twoByteChars(nogc), length_);
|
||||
}
|
||||
|
||||
UniqueChars ParserAtomToPrintableString(JSContext* cx, ParserAtomId atom) {
|
||||
const ParserAtomEntry* entry = atom.entry();
|
||||
Sprinter sprinter(cx);
|
||||
if (!sprinter.init()) {
|
||||
return nullptr;
|
||||
}
|
||||
size_t length = entry->length();
|
||||
if (entry->hasLatin1Chars()) {
|
||||
if (!QuoteString<QuoteTarget::String>(
|
||||
&sprinter, mozilla::Range(entry->latin1Chars(), length))) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
if (!QuoteString<QuoteTarget::String>(
|
||||
&sprinter, mozilla::Range(entry->twoByteChars(), length))) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return sprinter.release();
|
||||
}
|
||||
|
||||
bool ParserAtomEntry::isIndex(uint32_t* indexp) const {
|
||||
if (hasLatin1Chars()) {
|
||||
return js::CheckStringIsIndex(latin1Chars(), length(), indexp);
|
||||
}
|
||||
return js::CheckStringIsIndex(twoByteChars(), length(), indexp);
|
||||
}
|
||||
|
||||
JS::Result<JSAtom*, OOM&> ParserAtomEntry::toJSAtom(JSContext* cx) const {
|
||||
if (jsatom_) {
|
||||
return jsatom_;
|
||||
}
|
||||
|
||||
if (hasLatin1Chars()) {
|
||||
jsatom_ = AtomizeChars(cx, latin1Chars(), length());
|
||||
} else {
|
||||
jsatom_ = AtomizeChars(cx, twoByteChars(), length());
|
||||
}
|
||||
if (!jsatom_) {
|
||||
return RaiseParserAtomsOOMError(cx);
|
||||
}
|
||||
return jsatom_;
|
||||
}
|
||||
|
||||
bool ParserAtomEntry::toNumber(JSContext* cx, double* result) const {
|
||||
return hasLatin1Chars() ? CharsToNumber(cx, latin1Chars(), length(), result)
|
||||
: CharsToNumber(cx, twoByteChars(), length(), result);
|
||||
}
|
||||
|
||||
ParserAtomsTable::ParserAtomsTable(JSContext* cx)
|
||||
: entrySet_(cx), wellKnownTable_(*cx->runtime()->commonParserNames) {}
|
||||
|
||||
JS::Result<ParserAtomId, OOM&> ParserAtomsTable::addEntry(
|
||||
JSContext* cx, EntrySet::AddPtr addPtr, ParserAtomEntry&& entry) {
|
||||
UniquePtr<ParserAtomEntry> uniqueEntry(
|
||||
cx->new_<ParserAtomEntry>(std::move(entry)));
|
||||
if (!uniqueEntry) {
|
||||
return RaiseParserAtomsOOMError(cx);
|
||||
}
|
||||
ParserAtomEntry* entryPtr = uniqueEntry.get();
|
||||
|
||||
if (!entrySet_.add(addPtr, std::move(uniqueEntry))) {
|
||||
return RaiseParserAtomsOOMError(cx);
|
||||
}
|
||||
ParserAtomId id(entryPtr);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static const uint16_t MAX_LATIN1_CHAR = 0xff;
|
||||
|
||||
template <typename CharT, typename InCharT>
|
||||
static void DrainChar16Seq(CharT* buf, InflatedChar16Sequence<InCharT> seq) {
|
||||
static_assert(
|
||||
std::is_same_v<CharT, char16_t> || std::is_same_v<CharT, Latin1Char>,
|
||||
"Invalid target buffer type.");
|
||||
CharT* cur = buf;
|
||||
while (seq.hasMore()) {
|
||||
char16_t ch = seq.next();
|
||||
if constexpr (std::is_same_v<CharT, Latin1Char>) {
|
||||
MOZ_ASSERT(ch <= MAX_LATIN1_CHAR);
|
||||
}
|
||||
*cur = ch;
|
||||
cur++;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename AtomCharT, typename SeqCharT>
|
||||
JS::Result<ParserAtomId, OOM&> ParserAtomsTable::internChar16Seq(
|
||||
JSContext* cx, EntrySet::AddPtr add, InflatedChar16Sequence<SeqCharT> seq,
|
||||
uint32_t length, HashNumber hash) {
|
||||
using UniqueCharsT = mozilla::UniquePtr<AtomCharT[], JS::FreePolicy>;
|
||||
UniqueCharsT copy(cx->pod_malloc<AtomCharT>(length));
|
||||
if (!copy) {
|
||||
return RaiseParserAtomsOOMError(cx);
|
||||
}
|
||||
DrainChar16Seq<AtomCharT, SeqCharT>(copy.get(), seq);
|
||||
ParserAtomEntry ent = ParserAtomEntry::make(std::move(copy), length, hash);
|
||||
return addEntry(cx, add, std::move(ent));
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
JS::Result<ParserAtomId, OOM&> ParserAtomsTable::lookupOrInternChar16Seq(
|
||||
JSContext* cx, InflatedChar16Sequence<CharT> seq) {
|
||||
// Check against well-known.
|
||||
ParserAtomId wk = wellKnownTable_.lookupChar16Seq(seq);
|
||||
if (wk) {
|
||||
return wk;
|
||||
}
|
||||
|
||||
// Check for existing atom.
|
||||
SpecificParserAtomLookup<CharT> lookup(seq);
|
||||
EntrySet::AddPtr add = entrySet_.lookupForAdd(lookup);
|
||||
if (add) {
|
||||
return ParserAtomId(add->get());
|
||||
}
|
||||
|
||||
// Compute the total length and the storage requirements.
|
||||
bool wide = false;
|
||||
uint32_t length = 0;
|
||||
InflatedChar16Sequence<CharT> seqCopy = seq;
|
||||
while (seqCopy.hasMore()) {
|
||||
char16_t ch = seqCopy.next();
|
||||
wide = wide || (ch > MAX_LATIN1_CHAR);
|
||||
length += 1;
|
||||
}
|
||||
|
||||
HashNumber hash = lookup.hash();
|
||||
return wide ? internChar16Seq<char16_t>(cx, add, seq, length, hash)
|
||||
: internChar16Seq<Latin1Char>(cx, add, seq, length, hash);
|
||||
}
|
||||
|
||||
JS::Result<ParserAtomId, OOM&> ParserAtomsTable::internChar16(
|
||||
JSContext* cx, const char16_t* char16Ptr, uint32_t length) {
|
||||
InflatedChar16Sequence<char16_t> seq(char16Ptr, length);
|
||||
|
||||
return lookupOrInternChar16Seq(cx, seq);
|
||||
}
|
||||
|
||||
JS::Result<ParserAtomId, OOM&> ParserAtomsTable::internAscii(
|
||||
JSContext* cx, const char* asciiPtr, uint32_t length) {
|
||||
const Latin1Char* latin1Ptr = reinterpret_cast<const Latin1Char*>(asciiPtr);
|
||||
return internLatin1(cx, latin1Ptr, length);
|
||||
}
|
||||
|
||||
JS::Result<ParserAtomId, OOM&> ParserAtomsTable::internLatin1(
|
||||
JSContext* cx, const Latin1Char* latin1Ptr, uint32_t length) {
|
||||
// ASCII strings are strict subsets of Latin1 strings, an so can be used
|
||||
// in the same (const) ways.
|
||||
InflatedChar16Sequence<Latin1Char> seq(latin1Ptr, length);
|
||||
|
||||
// Check against well-known.
|
||||
ParserAtomId wk = wellKnownTable_.lookupChar16Seq(seq);
|
||||
if (wk) {
|
||||
return wk;
|
||||
}
|
||||
|
||||
// Look up.
|
||||
SpecificParserAtomLookup<Latin1Char> lookup(seq);
|
||||
EntrySet::AddPtr add = entrySet_.lookupForAdd(lookup);
|
||||
if (add) {
|
||||
return ParserAtomId(add->get());
|
||||
}
|
||||
|
||||
// Existing entry not found, heap-allocate a copy and add it to the table.
|
||||
UniqueLatin1Chars copy = js::DuplicateString(cx, latin1Ptr, length);
|
||||
if (!copy) {
|
||||
return RaiseParserAtomsOOMError(cx);
|
||||
}
|
||||
ParserAtomEntry ent =
|
||||
ParserAtomEntry::make(std::move(copy), length, lookup.hash());
|
||||
return addEntry(cx, add, std::move(ent));
|
||||
}
|
||||
|
||||
JS::Result<ParserAtomId, OOM&> ParserAtomsTable::internUtf8(
|
||||
JSContext* cx, const mozilla::Utf8Unit* utf8Ptr, uint32_t length) {
|
||||
// If source text is ASCII, then the length of the target char buffer
|
||||
// is the same as the length of the UTF8 input. Convert it to a Latin1
|
||||
// encoded string on the heap.
|
||||
UTF8Chars utf8(utf8Ptr, length);
|
||||
if (FindSmallestEncoding(utf8) == JS::SmallestEncoding::ASCII) {
|
||||
// As ascii strings are a subset of Latin1 strings, and each encoding
|
||||
// unit is the same size, we can reliably cast this `Utf8Unit*`
|
||||
// to a `Latin1Char*`.
|
||||
const Latin1Char* latin1Ptr = reinterpret_cast<const Latin1Char*>(utf8Ptr);
|
||||
return internLatin1(cx, latin1Ptr, length);
|
||||
}
|
||||
|
||||
InflatedChar16Sequence<mozilla::Utf8Unit> seq(utf8Ptr, length);
|
||||
|
||||
// Otherwise, slowpath lookup/interning path that identifies the
|
||||
// proper target encoding.
|
||||
return lookupOrInternChar16Seq(cx, seq);
|
||||
}
|
||||
|
||||
JS::Result<ParserAtomId, OOM&> ParserAtomsTable::internJSAtom(JSContext* cx,
|
||||
JSAtom* atom) {
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
|
||||
auto result =
|
||||
atom->hasLatin1Chars()
|
||||
? internLatin1(cx, atom->latin1Chars(nogc), atom->length())
|
||||
: internChar16(cx, atom->twoByteChars(nogc), atom->length());
|
||||
if (result.isErr()) {
|
||||
return result;
|
||||
}
|
||||
ParserAtomId id = result.unwrap();
|
||||
id.entry()->setAtom(atom);
|
||||
return id;
|
||||
}
|
||||
|
||||
static void FillChar16Buffer(char16_t* buf, const ParserAtomEntry* ent) {
|
||||
if (ent->hasLatin1Chars()) {
|
||||
std::copy(ent->latin1Chars(), ent->latin1Chars() + ent->length(), buf);
|
||||
} else {
|
||||
std::copy(ent->twoByteChars(), ent->twoByteChars() + ent->length(), buf);
|
||||
}
|
||||
}
|
||||
|
||||
JS::Result<ParserAtomId, OOM&> ParserAtomsTable::concatAtoms(
|
||||
JSContext* cx, ParserAtomId prefix, ParserAtomId suffix) {
|
||||
const ParserAtomEntry* prefixEntry = prefix.entry();
|
||||
const ParserAtomEntry* suffixEntry = suffix.entry();
|
||||
|
||||
bool latin1 = prefixEntry->hasLatin1Chars() && suffixEntry->hasLatin1Chars();
|
||||
size_t prefixLength = prefixEntry->length();
|
||||
size_t suffixLength = suffixEntry->length();
|
||||
size_t concatLength = prefixLength + suffixLength;
|
||||
|
||||
if (latin1) {
|
||||
// Concatenate a latin1 string and add it to the table.
|
||||
UniqueLatin1Chars copy(cx->pod_malloc<Latin1Char>(concatLength));
|
||||
if (!copy) {
|
||||
return RaiseParserAtomsOOMError(cx);
|
||||
}
|
||||
mozilla::PodCopy(copy.get(), prefixEntry->latin1Chars(), prefixLength);
|
||||
mozilla::PodCopy(copy.get() + prefixLength, suffixEntry->latin1Chars(),
|
||||
suffixLength);
|
||||
|
||||
InflatedChar16Sequence<Latin1Char> seq(copy.get(), concatLength);
|
||||
|
||||
// Check against well-known.
|
||||
ParserAtomId wk = wellKnownTable_.lookupChar16Seq(seq);
|
||||
if (wk) {
|
||||
return wk;
|
||||
}
|
||||
|
||||
SpecificParserAtomLookup<Latin1Char> lookup(seq);
|
||||
EntrySet::AddPtr add = entrySet_.lookupForAdd(lookup);
|
||||
if (add) {
|
||||
return ParserAtomId(add->get());
|
||||
}
|
||||
|
||||
ParserAtomEntry ent =
|
||||
ParserAtomEntry::make(std::move(copy), concatLength, lookup.hash());
|
||||
|
||||
return addEntry(cx, add, std::move(ent));
|
||||
}
|
||||
|
||||
// Concatenate a char16 string and add it to the table.
|
||||
UniqueTwoByteChars copy(cx->pod_malloc<char16_t>(concatLength));
|
||||
if (!copy) {
|
||||
return RaiseParserAtomsOOMError(cx);
|
||||
}
|
||||
FillChar16Buffer(copy.get(), prefixEntry);
|
||||
FillChar16Buffer(copy.get() + prefixLength, suffixEntry);
|
||||
|
||||
InflatedChar16Sequence<char16_t> seq(copy.get(), concatLength);
|
||||
|
||||
// Check against well-known.
|
||||
ParserAtomId wk = wellKnownTable_.lookupChar16Seq(seq);
|
||||
if (wk) {
|
||||
return wk;
|
||||
}
|
||||
|
||||
SpecificParserAtomLookup<char16_t> lookup(seq);
|
||||
EntrySet::AddPtr add = entrySet_.lookupForAdd(lookup);
|
||||
if (add) {
|
||||
return ParserAtomId(add->get());
|
||||
}
|
||||
|
||||
ParserAtomEntry ent =
|
||||
ParserAtomEntry::make(std::move(copy), concatLength, lookup.hash());
|
||||
|
||||
return addEntry(cx, add, std::move(ent));
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
ParserAtomId WellKnownParserAtoms::lookupChar16Seq(
|
||||
InflatedChar16Sequence<CharT> seq) const {
|
||||
SpecificParserAtomLookup<CharT> lookup(seq);
|
||||
EntrySet::Ptr get = entrySet_.readonlyThreadsafeLookup(lookup);
|
||||
if (get) {
|
||||
return ParserAtomId(get->get());
|
||||
}
|
||||
return ParserAtomId::Invalid();
|
||||
}
|
||||
|
||||
bool WellKnownParserAtoms::initSingle(JSContext* cx, ParserNameId* name,
|
||||
const char* str) {
|
||||
MOZ_ASSERT(name != nullptr);
|
||||
|
||||
unsigned int len = strlen(str);
|
||||
|
||||
MOZ_ASSERT(FindSmallestEncoding(UTF8Chars(str, len)) ==
|
||||
JS::SmallestEncoding::ASCII);
|
||||
|
||||
UniqueLatin1Chars copy(cx->pod_malloc<Latin1Char>(len));
|
||||
if (!copy) {
|
||||
return false;
|
||||
}
|
||||
mozilla::PodCopy(copy.get(), reinterpret_cast<const Latin1Char*>(str), len);
|
||||
|
||||
InflatedChar16Sequence<Latin1Char> seq(copy.get(), len);
|
||||
SpecificParserAtomLookup<Latin1Char> lookup(seq);
|
||||
|
||||
ParserAtomEntry ent =
|
||||
ParserAtomEntry::make(std::move(copy), len, lookup.hash());
|
||||
|
||||
UniquePtr<ParserAtomEntry> uniqueEntry(
|
||||
cx->new_<ParserAtomEntry>(std::move(ent)));
|
||||
if (!uniqueEntry) {
|
||||
return false;
|
||||
}
|
||||
ParserNameId nm(uniqueEntry.get());
|
||||
|
||||
if (!entrySet_.putNew(lookup, std::move(uniqueEntry))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*name = nm;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WellKnownParserAtoms::init(JSContext* cx) {
|
||||
#define COMMON_NAME_INIT(idpart, id, text) \
|
||||
if (!initSingle(cx, &(id), text)) { \
|
||||
return false; \
|
||||
}
|
||||
FOR_EACH_COMMON_PROPERTYNAME(COMMON_NAME_INIT)
|
||||
#undef COMMON_NAME_INIT
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* namespace frontend */
|
||||
} /* namespace js */
|
||||
|
||||
bool JSRuntime::initializeParserAtoms(JSContext* cx) {
|
||||
#ifdef JS_PARSER_ATOMS
|
||||
MOZ_ASSERT(!commonParserNames);
|
||||
|
||||
if (parentRuntime) {
|
||||
commonParserNames = parentRuntime->commonParserNames;
|
||||
return true;
|
||||
}
|
||||
|
||||
UniquePtr<js::frontend::WellKnownParserAtoms> names(
|
||||
js_new<js::frontend::WellKnownParserAtoms>(cx));
|
||||
if (!names || !names->init(cx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
commonParserNames = names.release();
|
||||
#else
|
||||
commonParserNames = nullptr;
|
||||
#endif // JS_PARSER_ATOMS
|
||||
return true;
|
||||
}
|
||||
|
||||
void JSRuntime::finishParserAtoms() {
|
||||
#ifdef JS_PARSER_ATOMS
|
||||
if (!parentRuntime) {
|
||||
js_delete(commonParserNames.ref());
|
||||
}
|
||||
#else
|
||||
MOZ_ASSERT(!commonParserNames);
|
||||
#endif // JS_PARSER_ATOMS
|
||||
}
|
360
js/src/frontend/ParserAtom.h
Normal file
360
js/src/frontend/ParserAtom.h
Normal file
@ -0,0 +1,360 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||
* 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/. */
|
||||
|
||||
#ifndef frontend_ParserAtom_h
|
||||
#define frontend_ParserAtom_h
|
||||
|
||||
#include "mozilla/HashFunctions.h" // HashString
|
||||
#include "mozilla/Variant.h" // mozilla::Variant
|
||||
|
||||
#include "ds/LifoAlloc.h" // LifoAlloc
|
||||
#include "js/HashTable.h" // HashSet
|
||||
#include "js/UniquePtr.h" // js::UniquePtr
|
||||
#include "js/Vector.h" // Vector
|
||||
#include "vm/CommonPropertyNames.h"
|
||||
#include "vm/StringType.h" // CompareChars, StringEqualsAscii
|
||||
|
||||
namespace js {
|
||||
namespace frontend {
|
||||
|
||||
class ParserNameId;
|
||||
|
||||
template <typename CharT>
|
||||
class SpecificParserAtomLookup;
|
||||
|
||||
class ParserAtomsTable;
|
||||
|
||||
mozilla::GenericErrorResult<OOM&> RaiseParserAtomsOOMError(JSContext* cx);
|
||||
|
||||
/**
|
||||
* A ParserAtomEntry is an in-parser representation of an interned atomic
|
||||
* string. It mostly mirrors the information carried by a JSAtom*.
|
||||
*
|
||||
* ParserAtomEntry structs are individually heap-allocated and own their
|
||||
* heap-allocated contents.
|
||||
*/
|
||||
class ParserAtomEntry {
|
||||
friend class ParserAtomsTable;
|
||||
|
||||
public:
|
||||
// Owned characters, either 8-bit Latin1, or 16-bit Char16
|
||||
mozilla::Variant<JS::UniqueLatin1Chars, JS::UniqueTwoByteChars> chars_;
|
||||
|
||||
// The length of the buffer in chars_.
|
||||
uint32_t length_;
|
||||
|
||||
// The JSAtom-compatible hash of the string.
|
||||
HashNumber hash_;
|
||||
|
||||
// Used to dynamically optimize the mapping of ParserAtoms to JSAtom*s.
|
||||
// If the entry comes from an atom or has been mapped to an
|
||||
// atom previously, the atom reference is kept here.
|
||||
mutable JSAtom* jsatom_ = nullptr;
|
||||
|
||||
template <typename CharsT>
|
||||
ParserAtomEntry(CharsT&& chars, uint32_t length, HashNumber hash)
|
||||
: chars_(std::forward<CharsT&&>(chars)), length_(length), hash_(hash) {}
|
||||
|
||||
public:
|
||||
// ParserAtomEntries own their content buffers in chars_, and thus cannot
|
||||
// be copy-constructed - as a new chars would need to be allocated.
|
||||
ParserAtomEntry(const ParserAtomEntry&) = delete;
|
||||
|
||||
ParserAtomEntry(ParserAtomEntry&& other) = default;
|
||||
|
||||
template <typename CharT>
|
||||
static ParserAtomEntry make(mozilla::UniquePtr<CharT[], JS::FreePolicy>&& ptr,
|
||||
uint32_t length, HashNumber hash) {
|
||||
return ParserAtomEntry(std::move(ptr), length, hash);
|
||||
}
|
||||
|
||||
bool hasLatin1Chars() const { return chars_.is<UniqueLatin1Chars>(); }
|
||||
bool hasTwoByteChars() const { return chars_.is<UniqueTwoByteChars>(); }
|
||||
|
||||
const Latin1Char* latin1Chars() const {
|
||||
MOZ_ASSERT(hasLatin1Chars());
|
||||
return chars_.as<UniqueLatin1Chars>().get();
|
||||
}
|
||||
const char16_t* twoByteChars() const {
|
||||
MOZ_ASSERT(hasTwoByteChars());
|
||||
return chars_.as<UniqueTwoByteChars>().get();
|
||||
}
|
||||
|
||||
bool isIndex(uint32_t* indexp) const;
|
||||
|
||||
HashNumber hash() const { return hash_; }
|
||||
uint32_t length() const { return length_; }
|
||||
|
||||
bool equalsJSAtom(JSAtom* other) const;
|
||||
|
||||
template <typename CharT>
|
||||
bool equalsSeq(HashNumber hash, InflatedChar16Sequence<CharT> seq) const;
|
||||
|
||||
void setAtom(JSAtom* atom) const {
|
||||
MOZ_ASSERT(atom != nullptr);
|
||||
if (jsatom_ != nullptr) {
|
||||
MOZ_ASSERT(jsatom_ == atom);
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(equalsJSAtom(atom));
|
||||
jsatom_ = atom;
|
||||
}
|
||||
|
||||
// Convert this entry to a js-atom. The first time this method is called
|
||||
// the entry will cache the JSAtom pointer to return later.
|
||||
JS::Result<JSAtom*, OOM&> toJSAtom(JSContext* cx) const;
|
||||
|
||||
// Convert this entry to a number.
|
||||
bool toNumber(JSContext* cx, double* result) const;
|
||||
};
|
||||
|
||||
class ParserAtomId {
|
||||
protected:
|
||||
const ParserAtomEntry* entry_;
|
||||
|
||||
struct InitInvalid {};
|
||||
|
||||
explicit ParserAtomId(InitInvalid) : entry_(nullptr) {}
|
||||
|
||||
public:
|
||||
explicit ParserAtomId(const ParserAtomEntry* entry) : entry_(entry) {
|
||||
MOZ_ASSERT(entry_ != nullptr);
|
||||
}
|
||||
ParserAtomId() = default;
|
||||
|
||||
bool isValid() const { return entry_ != nullptr; }
|
||||
const ParserAtomEntry* entry() const {
|
||||
MOZ_ASSERT(isValid());
|
||||
return entry_;
|
||||
}
|
||||
MOZ_IMPLICIT operator bool() const { return isValid(); }
|
||||
|
||||
static ParserAtomId Invalid() { return ParserAtomId(InitInvalid{}); }
|
||||
|
||||
// As the "unchecked" tag signifies, this method should only be called
|
||||
// after it has been confirmed that this atom is a name and not an index.
|
||||
inline ParserNameId toNameIdUnchecked() const;
|
||||
|
||||
bool operator==(const ParserAtomId& other) { return entry_ == other.entry_; }
|
||||
bool operator!=(const ParserAtomId& other) { return !(*this == other); }
|
||||
|
||||
bool isIndex(uint32_t* indexp) const { return entry()->isIndex(indexp); }
|
||||
bool equalsJSAtom(JSAtom* other) const {
|
||||
return entry()->equalsJSAtom(other);
|
||||
}
|
||||
|
||||
size_t length() const { return entry()->length(); }
|
||||
size_t empty() const { return length() == 0; }
|
||||
|
||||
struct Hasher {
|
||||
using Lookup = ParserAtomId;
|
||||
|
||||
static inline HashNumber hash(const Lookup& l) {
|
||||
return DefaultHasher<const ParserAtomEntry*>::hash(l.entry());
|
||||
}
|
||||
static inline bool match(const ParserAtomId& entry,
|
||||
const ParserAtomId& lookup) {
|
||||
return lookup == entry;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class ParserNameId : public ParserAtomId {
|
||||
explicit ParserNameId(InitInvalid) : ParserAtomId(InitInvalid{}) {}
|
||||
|
||||
public:
|
||||
ParserNameId() = default;
|
||||
explicit ParserNameId(const ParserAtomEntry* entry) : ParserAtomId(entry) {}
|
||||
ParserNameId(const ParserNameId& other) = default;
|
||||
|
||||
static ParserNameId Invalid() { return ParserNameId(InitInvalid{}); }
|
||||
};
|
||||
|
||||
inline ParserNameId ParserAtomId::toNameIdUnchecked() const {
|
||||
return ParserNameId(entry_);
|
||||
}
|
||||
|
||||
UniqueChars ParserAtomToPrintableString(JSContext* cx, ParserAtomId atom);
|
||||
|
||||
/**
|
||||
* A lookup structure that allows for querying ParserAtoms in
|
||||
* a hashtable using a flexible input type that supports string
|
||||
* representations of various forms.
|
||||
*/
|
||||
class ParserAtomLookup {
|
||||
protected:
|
||||
HashNumber hash_;
|
||||
|
||||
ParserAtomLookup(HashNumber hash) : hash_(hash) {}
|
||||
|
||||
public:
|
||||
HashNumber hash() const { return hash_; }
|
||||
|
||||
virtual bool equalsEntry(const ParserAtomEntry* entry) const = 0;
|
||||
};
|
||||
|
||||
struct ParserAtomLookupHasher {
|
||||
using Lookup = ParserAtomLookup;
|
||||
|
||||
static inline HashNumber hash(const Lookup& l) { return l.hash(); }
|
||||
static inline bool match(const UniquePtr<ParserAtomEntry>& entry,
|
||||
const Lookup& l) {
|
||||
return l.equalsEntry(entry.get());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* WellKnown maintains a well-structured reference to common names.
|
||||
* A single instance of it is held on the main Runtime, and allows
|
||||
* for the looking up of names, but not addition after initialization.
|
||||
*/
|
||||
class WellKnownParserAtoms {
|
||||
public:
|
||||
/* Various built-in or commonly-used names. */
|
||||
#define PROPERTYNAME_FIELD(idpart, id, text) ParserNameId id{};
|
||||
FOR_EACH_COMMON_PROPERTYNAME(PROPERTYNAME_FIELD)
|
||||
#undef PROPERTYNAME_FIELD
|
||||
|
||||
private:
|
||||
using EntrySet = HashSet<UniquePtr<ParserAtomEntry>, ParserAtomLookupHasher,
|
||||
TempAllocPolicy>;
|
||||
EntrySet entrySet_;
|
||||
|
||||
bool initSingle(JSContext* cx, ParserNameId* name, const char* str);
|
||||
|
||||
public:
|
||||
explicit WellKnownParserAtoms(JSContext* cx) : entrySet_(cx) {}
|
||||
|
||||
bool init(JSContext* cx);
|
||||
|
||||
template <typename CharT>
|
||||
ParserAtomId lookupChar16Seq(InflatedChar16Sequence<CharT> seq) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* A ParserAtomsTable owns and manages the vector of ParserAtom entries
|
||||
* associated with a given compile session.
|
||||
*/
|
||||
class ParserAtomsTable {
|
||||
private:
|
||||
using EntrySet = HashSet<UniquePtr<ParserAtomEntry>, ParserAtomLookupHasher,
|
||||
TempAllocPolicy>;
|
||||
EntrySet entrySet_;
|
||||
const WellKnownParserAtoms& wellKnownTable_;
|
||||
|
||||
public:
|
||||
explicit ParserAtomsTable(JSContext* cx);
|
||||
|
||||
private:
|
||||
JS::Result<ParserAtomId, OOM&> addEntry(JSContext* cx,
|
||||
EntrySet::AddPtr addPtr,
|
||||
ParserAtomEntry&& entry);
|
||||
|
||||
template <typename AtomCharT, typename SeqCharT>
|
||||
JS::Result<ParserAtomId, OOM&> internChar16Seq(
|
||||
JSContext* cx, EntrySet::AddPtr add, InflatedChar16Sequence<SeqCharT> seq,
|
||||
uint32_t length, HashNumber hash);
|
||||
|
||||
template <typename CharT>
|
||||
JS::Result<ParserAtomId, OOM&> lookupOrInternChar16Seq(
|
||||
JSContext* cx, InflatedChar16Sequence<CharT> seq);
|
||||
|
||||
public:
|
||||
JS::Result<ParserAtomId, OOM&> internChar16(JSContext* cx,
|
||||
const char16_t* char16Ptr,
|
||||
uint32_t length);
|
||||
|
||||
JS::Result<ParserAtomId, OOM&> internAscii(JSContext* cx,
|
||||
const char* asciiPtr,
|
||||
uint32_t length);
|
||||
|
||||
JS::Result<ParserAtomId, OOM&> internLatin1(JSContext* cx,
|
||||
const Latin1Char* latin1Ptr,
|
||||
uint32_t length);
|
||||
|
||||
JS::Result<ParserAtomId, OOM&> internUtf8(JSContext* cx,
|
||||
const mozilla::Utf8Unit* utf8Ptr,
|
||||
uint32_t length);
|
||||
|
||||
JS::Result<ParserAtomId, OOM&> internJSAtom(JSContext* cx, JSAtom* atom);
|
||||
|
||||
JS::Result<ParserAtomId, OOM&> concatAtoms(JSContext* cx, ParserAtomId prefix,
|
||||
ParserAtomId suffix);
|
||||
|
||||
// Lift this code
|
||||
// Once all the parser code has been changed to use a ParserAtomId, these
|
||||
// can go away.
|
||||
JS::Result<JSAtom*, OOM&> toJSAtom(JSContext* cx, ParserAtomId id) const {
|
||||
return id.entry()->toJSAtom(cx);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CharT>
|
||||
class SpecificParserAtomLookup : public ParserAtomLookup {
|
||||
// The sequence of characters to look up.
|
||||
InflatedChar16Sequence<CharT> seq_;
|
||||
|
||||
public:
|
||||
explicit SpecificParserAtomLookup(const InflatedChar16Sequence<CharT>& seq)
|
||||
: SpecificParserAtomLookup(seq, computeHash(seq)) {}
|
||||
|
||||
SpecificParserAtomLookup(const InflatedChar16Sequence<CharT>& seq,
|
||||
HashNumber hash)
|
||||
: ParserAtomLookup(hash), seq_(seq) {
|
||||
MOZ_ASSERT(computeHash(seq_) == hash);
|
||||
}
|
||||
|
||||
virtual bool equalsEntry(const ParserAtomEntry* entry) const override {
|
||||
return entry->equalsSeq<CharT>(hash_, seq_);
|
||||
}
|
||||
|
||||
private:
|
||||
static HashNumber computeHash(InflatedChar16Sequence<CharT> seq) {
|
||||
HashNumber hash = 0;
|
||||
while (seq.hasMore()) {
|
||||
hash = mozilla::AddToHash(hash, seq.next());
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CharT>
|
||||
inline bool ParserAtomEntry::equalsSeq(
|
||||
HashNumber hash, InflatedChar16Sequence<CharT> seq) const {
|
||||
// Compare hashes first.
|
||||
if (hash_ != hash) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasTwoByteChars()) {
|
||||
const char16_t* chars = twoByteChars();
|
||||
for (uint32_t i = 0; i < length_; i++) {
|
||||
if (!seq.hasMore() || chars[i] != seq.next()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (seq.hasMore()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
const Latin1Char* chars = latin1Chars();
|
||||
for (uint32_t i = 0; i < length_; i++) {
|
||||
if (!seq.hasMore() || char16_t(chars[i]) != seq.next()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (seq.hasMore()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* namespace frontend */
|
||||
} /* namespace js */
|
||||
|
||||
#endif // frontend_ParserAtom_h
|
@ -2231,7 +2231,7 @@ MOZ_MUST_USE bool TokenStreamSpecific<Unit, AnyCharsAccess>::identifierName(
|
||||
return false;
|
||||
}
|
||||
|
||||
atom = drainCharBufferIntoAtom(anyCharsAccess().cx);
|
||||
atom = drainCharBufferIntoAtom();
|
||||
} else {
|
||||
// Escape-free identifiers can be created directly from sourceUnits.
|
||||
const Unit* chars = identStart;
|
||||
@ -2247,7 +2247,7 @@ MOZ_MUST_USE bool TokenStreamSpecific<Unit, AnyCharsAccess>::identifierName(
|
||||
}
|
||||
}
|
||||
|
||||
atom = atomizeSourceChars(anyCharsAccess().cx, MakeSpan(chars, length));
|
||||
atom = atomizeSourceChars(MakeSpan(chars, length));
|
||||
}
|
||||
if (!atom) {
|
||||
return false;
|
||||
@ -3668,7 +3668,7 @@ bool TokenStreamSpecific<Unit, AnyCharsAccess>::getStringOrTemplateToken(
|
||||
}
|
||||
}
|
||||
|
||||
JSAtom* atom = drainCharBufferIntoAtom(anyCharsAccess().cx);
|
||||
JSAtom* atom = drainCharBufferIntoAtom();
|
||||
if (!atom) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1537,8 +1537,22 @@ class TokenStreamCharsShared {
|
||||
return mozilla::IsAscii(static_cast<char32_t>(unit));
|
||||
}
|
||||
|
||||
JSAtom* drainCharBufferIntoAtom(JSContext* cx) {
|
||||
JSAtom* atom = AtomizeChars(cx, charBuffer.begin(), charBuffer.length());
|
||||
JSAtom* drainCharBufferIntoAtom() {
|
||||
JSAtom* atom = AtomizeChars(this->compilationInfo->cx, charBuffer.begin(),
|
||||
charBuffer.length());
|
||||
if (!atom) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Add to parser atoms table.
|
||||
#ifdef JS_PARSER_ATOMS
|
||||
auto maybeId = this->compilationInfo->parserAtoms.internChar16(
|
||||
this->compilationInfo->cx, charBuffer.begin(), charBuffer.length());
|
||||
if (maybeId.isErr()) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif // JS_PARSER_ATOMS
|
||||
|
||||
charBuffer.clear();
|
||||
return atom;
|
||||
}
|
||||
@ -1602,8 +1616,7 @@ class TokenStreamCharsBase : public TokenStreamCharsShared {
|
||||
sourceUnits.ungetCodeUnit();
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE JSAtom* atomizeSourceChars(
|
||||
JSContext* cx, mozilla::Span<const Unit> units);
|
||||
MOZ_ALWAYS_INLINE JSAtom* atomizeSourceChars(mozilla::Span<const Unit> units);
|
||||
|
||||
/**
|
||||
* Try to match a non-LineTerminator ASCII code point. Return true iff it
|
||||
@ -1689,18 +1702,45 @@ inline void TokenStreamCharsBase<Unit>::consumeKnownCodeUnit(int32_t unit) {
|
||||
}
|
||||
|
||||
template <>
|
||||
/* static */ MOZ_ALWAYS_INLINE JSAtom*
|
||||
TokenStreamCharsBase<char16_t>::atomizeSourceChars(
|
||||
JSContext* cx, mozilla::Span<const char16_t> units) {
|
||||
return AtomizeChars(cx, units.data(), units.size());
|
||||
MOZ_ALWAYS_INLINE JSAtom* TokenStreamCharsBase<char16_t>::atomizeSourceChars(
|
||||
mozilla::Span<const char16_t> units) {
|
||||
JSAtom* atom =
|
||||
AtomizeChars(this->compilationInfo->cx, units.data(), units.size());
|
||||
if (!atom) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef JS_PARSER_ATOMS
|
||||
auto maybeId = this->compilationInfo->parserAtoms.internChar16(
|
||||
this->compilationInfo->cx, units.data(), units.size());
|
||||
if (maybeId.isErr()) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif // JS_PARSER_ATOMS
|
||||
|
||||
return atom;
|
||||
}
|
||||
|
||||
template <>
|
||||
/* static */ MOZ_ALWAYS_INLINE JSAtom*
|
||||
TokenStreamCharsBase<mozilla::Utf8Unit>::atomizeSourceChars(
|
||||
JSContext* cx, mozilla::Span<const mozilla::Utf8Unit> units) {
|
||||
mozilla::Span<const mozilla::Utf8Unit> units) {
|
||||
auto chars = ToCharSpan(units);
|
||||
return AtomizeUTF8Chars(cx, chars.data(), chars.size());
|
||||
JSAtom* atom =
|
||||
AtomizeUTF8Chars(this->compilationInfo->cx, chars.data(), chars.size());
|
||||
if (!atom) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef JS_PARSER_ATOMS
|
||||
auto maybeId = this->compilationInfo->parserAtoms.internUtf8(
|
||||
this->compilationInfo->cx, units.data(), units.size());
|
||||
if (maybeId.isErr()) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif // JS_PARSER_ATOMS
|
||||
|
||||
return atom;
|
||||
}
|
||||
|
||||
template <typename Unit>
|
||||
@ -2141,7 +2181,7 @@ class GeneralTokenStreamChars : public SpecializedTokenStreamCharsBase<Unit> {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return drainCharBufferIntoAtom(anyChars.cx);
|
||||
return drainCharBufferIntoAtom();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -58,6 +58,7 @@ UNIFIED_SOURCES += [
|
||||
'ParseContext.cpp',
|
||||
'ParseNode.cpp',
|
||||
'ParseNodeVerify.cpp',
|
||||
'ParserAtom.cpp',
|
||||
'PropOpEmitter.cpp',
|
||||
'SharedContext.cpp',
|
||||
'SourceNotes.cpp',
|
||||
|
@ -464,6 +464,10 @@ JS_PUBLIC_API bool JS::InitSelfHostedCode(JSContext* cx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!rt->initializeParserAtoms(cx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef JS_CODEGEN_NONE
|
||||
if (!rt->createJitRuntime(cx)) {
|
||||
return false;
|
||||
|
@ -1661,7 +1661,7 @@ bool JS_FASTCALL js::NumberValueToStringBuffer(JSContext* cx, const Value& v,
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
static bool CharsToNumber(JSContext* cx, const CharT* chars, size_t length,
|
||||
static bool CharsToNumberImpl(JSContext* cx, const CharT* chars, size_t length,
|
||||
double* result) {
|
||||
if (length == 1) {
|
||||
CharT c = chars[0];
|
||||
@ -1731,6 +1731,16 @@ static bool CharsToNumber(JSContext* cx, const CharT* chars, size_t length,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool js::CharsToNumber(JSContext* cx, const Latin1Char* chars, size_t length,
|
||||
double* result) {
|
||||
return CharsToNumberImpl(cx, chars, length, result);
|
||||
}
|
||||
|
||||
bool js::CharsToNumber(JSContext* cx, const char16_t* chars, size_t length,
|
||||
double* result) {
|
||||
return CharsToNumberImpl(cx, chars, length, result);
|
||||
}
|
||||
|
||||
bool js::StringToNumber(JSContext* cx, JSString* str, double* result) {
|
||||
AutoCheckCannotGC nogc;
|
||||
JSLinearString* linearStr = str->ensureLinear(cx);
|
||||
|
@ -176,6 +176,11 @@ template <typename CharT>
|
||||
extern MOZ_MUST_USE bool GetDecimalNonInteger(JSContext* cx, const CharT* start,
|
||||
const CharT* end, double* dp);
|
||||
|
||||
bool CharsToNumber(JSContext* cx, const Latin1Char* chars, size_t length,
|
||||
double* result);
|
||||
bool CharsToNumber(JSContext* cx, const char16_t* chars, size_t length,
|
||||
double* result);
|
||||
|
||||
extern MOZ_MUST_USE bool StringToNumber(JSContext* cx, JSString* str,
|
||||
double* result);
|
||||
|
||||
|
@ -73,6 +73,19 @@ UniqueChars js::DuplicateStringToArena(arena_id_t destArenaId, JSContext* cx,
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniqueLatin1Chars js::DuplicateStringToArena(arena_id_t destArenaId,
|
||||
JSContext* cx,
|
||||
const JS::Latin1Char* s,
|
||||
size_t n) {
|
||||
auto ret = cx->make_pod_arena_array<Latin1Char>(destArenaId, n + 1);
|
||||
if (!ret) {
|
||||
return nullptr;
|
||||
}
|
||||
PodCopy(ret.get(), s, n);
|
||||
ret[n] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniqueTwoByteChars js::DuplicateStringToArena(arena_id_t destArenaId,
|
||||
JSContext* cx,
|
||||
const char16_t* s) {
|
||||
@ -106,6 +119,19 @@ UniqueChars js::DuplicateStringToArena(arena_id_t destArenaId, const char* s,
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniqueLatin1Chars js::DuplicateStringToArena(arena_id_t destArenaId,
|
||||
const JS::Latin1Char* s,
|
||||
size_t n) {
|
||||
UniqueLatin1Chars ret(
|
||||
js_pod_arena_malloc<JS::Latin1Char>(destArenaId, n + 1));
|
||||
if (!ret) {
|
||||
return nullptr;
|
||||
}
|
||||
PodCopy(ret.get(), s, n);
|
||||
ret[n] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
UniqueTwoByteChars js::DuplicateStringToArena(arena_id_t destArenaId,
|
||||
const char16_t* s) {
|
||||
return DuplicateStringToArena(destArenaId, s, js_strlen(s));
|
||||
@ -130,6 +156,11 @@ UniqueChars js::DuplicateString(JSContext* cx, const char* s) {
|
||||
return DuplicateStringToArena(js::MallocArena, cx, s);
|
||||
}
|
||||
|
||||
UniqueLatin1Chars js::DuplicateString(JSContext* cx, const JS::Latin1Char* s,
|
||||
size_t n) {
|
||||
return DuplicateStringToArena(js::MallocArena, cx, s, n);
|
||||
}
|
||||
|
||||
UniqueTwoByteChars js::DuplicateString(JSContext* cx, const char16_t* s) {
|
||||
return DuplicateStringToArena(js::MallocArena, cx, s);
|
||||
}
|
||||
@ -147,6 +178,10 @@ UniqueChars js::DuplicateString(const char* s, size_t n) {
|
||||
return DuplicateStringToArena(js::MallocArena, s, n);
|
||||
}
|
||||
|
||||
UniqueLatin1Chars js::DuplicateString(const JS::Latin1Char* s, size_t n) {
|
||||
return DuplicateStringToArena(js::MallocArena, s, n);
|
||||
}
|
||||
|
||||
UniqueTwoByteChars js::DuplicateString(const char16_t* s) {
|
||||
return DuplicateStringToArena(js::MallocArena, s);
|
||||
}
|
||||
|
@ -108,6 +108,10 @@ extern UniqueChars DuplicateStringToArena(arena_id_t destArenaId, JSContext* cx,
|
||||
extern UniqueChars DuplicateStringToArena(arena_id_t destArenaId, JSContext* cx,
|
||||
const char* s, size_t n);
|
||||
|
||||
extern UniqueLatin1Chars DuplicateStringToArena(arena_id_t destArenaId,
|
||||
JSContext* cx,
|
||||
const Latin1Char* s, size_t n);
|
||||
|
||||
extern UniqueTwoByteChars DuplicateStringToArena(arena_id_t destArenaId,
|
||||
JSContext* cx,
|
||||
const char16_t* s);
|
||||
@ -126,6 +130,10 @@ extern UniqueChars DuplicateStringToArena(arena_id_t destArenaId,
|
||||
extern UniqueChars DuplicateStringToArena(arena_id_t destArenaId, const char* s,
|
||||
size_t n);
|
||||
|
||||
extern UniqueLatin1Chars DuplicateStringToArena(arena_id_t destArenaId,
|
||||
const JS::Latin1Char* s,
|
||||
size_t n);
|
||||
|
||||
extern UniqueTwoByteChars DuplicateStringToArena(arena_id_t destArenaId,
|
||||
const char16_t* s);
|
||||
|
||||
@ -136,6 +144,9 @@ extern UniqueChars DuplicateString(JSContext* cx, const char* s);
|
||||
|
||||
extern UniqueChars DuplicateString(JSContext* cx, const char* s, size_t n);
|
||||
|
||||
extern UniqueLatin1Chars DuplicateString(JSContext* cx, const JS::Latin1Char* s,
|
||||
size_t n);
|
||||
|
||||
extern UniqueTwoByteChars DuplicateString(JSContext* cx, const char16_t* s);
|
||||
|
||||
extern UniqueTwoByteChars DuplicateString(JSContext* cx, const char16_t* s,
|
||||
@ -149,6 +160,8 @@ extern UniqueChars DuplicateString(const char* s);
|
||||
|
||||
extern UniqueChars DuplicateString(const char* s, size_t n);
|
||||
|
||||
extern UniqueLatin1Chars DuplicateString(const JS::Latin1Char* s, size_t n);
|
||||
|
||||
extern UniqueTwoByteChars DuplicateString(const char16_t* s);
|
||||
|
||||
extern UniqueTwoByteChars DuplicateString(const char16_t* s, size_t n);
|
||||
|
@ -40,6 +40,10 @@ class AutoAllocInAtomsZone;
|
||||
class AutoMaybeLeaveAtomsZone;
|
||||
class AutoRealm;
|
||||
|
||||
namespace frontend {
|
||||
class WellKnownParserAtoms;
|
||||
} // namespace frontend
|
||||
|
||||
namespace jit {
|
||||
class JitActivation;
|
||||
class JitContext;
|
||||
@ -265,6 +269,9 @@ struct JS_PUBLIC_API JSContext : public JS::RootingContext,
|
||||
|
||||
// Accessors for immutable runtime data.
|
||||
JSAtomState& names() { return *runtime_->commonNames; }
|
||||
js::frontend::WellKnownParserAtoms& parserNames() {
|
||||
return *runtime_->commonParserNames;
|
||||
}
|
||||
js::StaticStrings& staticStrings() { return *runtime_->staticStrings; }
|
||||
js::SharedImmutableStringsCache& sharedImmutableStrings() {
|
||||
return runtime_->sharedImmutableStrings();
|
||||
|
@ -109,6 +109,10 @@ class Simulator;
|
||||
#endif
|
||||
} // namespace jit
|
||||
|
||||
namespace frontend {
|
||||
class WellKnownParserAtoms;
|
||||
} // namespace frontend
|
||||
|
||||
// [SMDOC] JS Engine Threading
|
||||
//
|
||||
// Threads interacting with a runtime are divided into two categories:
|
||||
@ -742,7 +746,9 @@ struct JSRuntime {
|
||||
|
||||
public:
|
||||
bool initializeAtoms(JSContext* cx);
|
||||
bool initializeParserAtoms(JSContext* cx);
|
||||
void finishAtoms();
|
||||
void finishParserAtoms();
|
||||
bool atomsAreFinished() const {
|
||||
return !atoms_ && !permanentAtomsDuringInit_;
|
||||
}
|
||||
@ -783,6 +789,7 @@ struct JSRuntime {
|
||||
|
||||
// Cached pointers to various permanent property names.
|
||||
js::WriteOnceData<JSAtomState*> commonNames;
|
||||
js::WriteOnceData<js::frontend::WellKnownParserAtoms*> commonParserNames;
|
||||
|
||||
// All permanent atoms in the runtime, other than those in staticStrings.
|
||||
// Access to this does not require a lock because it is frozen and thus
|
||||
|
@ -1152,9 +1152,7 @@ bool js::StringEqualsAscii(JSLinearString* str, const char* asciiBytes,
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
/* static */
|
||||
bool JSLinearString::isIndexSlow(const CharT* s, size_t length,
|
||||
uint32_t* indexp) {
|
||||
bool js::CheckStringIsIndex(const CharT* s, size_t length, uint32_t* indexp) {
|
||||
MOZ_ASSERT(length > 0);
|
||||
MOZ_ASSERT(length <= UINT32_CHAR_BUFFER_LENGTH);
|
||||
MOZ_ASSERT(IsAsciiDigit(*s),
|
||||
@ -1194,6 +1192,18 @@ bool JSLinearString::isIndexSlow(const CharT* s, size_t length,
|
||||
return false;
|
||||
}
|
||||
|
||||
template bool js::CheckStringIsIndex(const Latin1Char* s, size_t length,
|
||||
uint32_t* indexp);
|
||||
template bool js::CheckStringIsIndex(const char16_t* s, size_t length,
|
||||
uint32_t* indexp);
|
||||
|
||||
template <typename CharT>
|
||||
/* static */
|
||||
bool JSLinearString::isIndexSlow(const CharT* s, size_t length,
|
||||
uint32_t* indexp) {
|
||||
return js::CheckStringIsIndex(s, length, indexp);
|
||||
}
|
||||
|
||||
template bool JSLinearString::isIndexSlow(const Latin1Char* s, size_t length,
|
||||
uint32_t* indexp);
|
||||
|
||||
|
@ -1259,6 +1259,9 @@ MOZ_ALWAYS_INLINE JSAtom* JSLinearString::morphAtomizedStringIntoPermanentAtom(
|
||||
|
||||
namespace js {
|
||||
|
||||
template <typename CharT>
|
||||
bool CheckStringIsIndex(const CharT* s, size_t length, uint32_t* indexp);
|
||||
|
||||
/**
|
||||
* An indexable characters class exposing unaligned, little-endian encoded
|
||||
* char16_t data.
|
||||
|
Loading…
Reference in New Issue
Block a user