зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
24a7deb2a4
Коммит
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_PUNBOX64', depends(target)(lambda t: t.bitness == 64 or None))
|
||||||
set_define('JS_NUNBOX32', depends(target)(lambda t: t.bitness == 32 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
|
# SpiderMonkey as a shared library, and how its symbols are exported
|
||||||
# ==================================================================
|
# ==================================================================
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "jstypes.h"
|
#include "jstypes.h"
|
||||||
#include "mozmemory.h"
|
#include "mozmemory.h"
|
||||||
|
#include "js/TypeDecls.h"
|
||||||
|
|
||||||
/* The public JS engine namespace. */
|
/* The public JS engine namespace. */
|
||||||
namespace JS {}
|
namespace JS {}
|
||||||
|
@ -650,6 +651,7 @@ struct FreePolicy {
|
||||||
|
|
||||||
typedef mozilla::UniquePtr<char[], JS::FreePolicy> UniqueChars;
|
typedef mozilla::UniquePtr<char[], JS::FreePolicy> UniqueChars;
|
||||||
typedef mozilla::UniquePtr<char16_t[], JS::FreePolicy> UniqueTwoByteChars;
|
typedef mozilla::UniquePtr<char16_t[], JS::FreePolicy> UniqueTwoByteChars;
|
||||||
|
typedef mozilla::UniquePtr<JS::Latin1Char[], JS::FreePolicy> UniqueLatin1Chars;
|
||||||
|
|
||||||
} // namespace JS
|
} // namespace JS
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,7 @@ using JS::Latin1CharsZ;
|
||||||
using JS::TwoByteChars;
|
using JS::TwoByteChars;
|
||||||
using JS::TwoByteCharsZ;
|
using JS::TwoByteCharsZ;
|
||||||
using JS::UniqueChars;
|
using JS::UniqueChars;
|
||||||
|
using JS::UniqueLatin1Chars;
|
||||||
using JS::UniqueTwoByteChars;
|
using JS::UniqueTwoByteChars;
|
||||||
using JS::UTF8Chars;
|
using JS::UTF8Chars;
|
||||||
using JS::UTF8CharsZ;
|
using JS::UTF8CharsZ;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "mozilla/Variant.h"
|
#include "mozilla/Variant.h"
|
||||||
|
|
||||||
#include "ds/LifoAlloc.h"
|
#include "ds/LifoAlloc.h"
|
||||||
|
#include "frontend/ParserAtom.h"
|
||||||
#include "frontend/SharedContext.h"
|
#include "frontend/SharedContext.h"
|
||||||
#include "frontend/Stencil.h"
|
#include "frontend/Stencil.h"
|
||||||
#include "frontend/UsedNameTracker.h"
|
#include "frontend/UsedNameTracker.h"
|
||||||
|
@ -75,6 +76,9 @@ struct MOZ_RAII CompilationInfo : public JS::CustomAutoRooter {
|
||||||
// onto them.
|
// onto them.
|
||||||
AutoKeepAtoms keepAtoms;
|
AutoKeepAtoms keepAtoms;
|
||||||
|
|
||||||
|
// Table of parser atoms for this compilation.
|
||||||
|
ParserAtomsTable parserAtoms;
|
||||||
|
|
||||||
Directives directives;
|
Directives directives;
|
||||||
|
|
||||||
ScopeContext scopeContext;
|
ScopeContext scopeContext;
|
||||||
|
@ -142,6 +146,7 @@ struct MOZ_RAII CompilationInfo : public JS::CustomAutoRooter {
|
||||||
cx(cx),
|
cx(cx),
|
||||||
options(options),
|
options(options),
|
||||||
keepAtoms(cx),
|
keepAtoms(cx),
|
||||||
|
parserAtoms(cx),
|
||||||
directives(options.forceStrictMode()),
|
directives(options.forceStrictMode()),
|
||||||
scopeContext(enclosingScope, enclosingEnv),
|
scopeContext(enclosingScope, enclosingEnv),
|
||||||
script(cx),
|
script(cx),
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
atom = drainCharBufferIntoAtom(anyCharsAccess().cx);
|
atom = drainCharBufferIntoAtom();
|
||||||
} else {
|
} else {
|
||||||
// Escape-free identifiers can be created directly from sourceUnits.
|
// Escape-free identifiers can be created directly from sourceUnits.
|
||||||
const Unit* chars = identStart;
|
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) {
|
if (!atom) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -3668,7 +3668,7 @@ bool TokenStreamSpecific<Unit, AnyCharsAccess>::getStringOrTemplateToken(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JSAtom* atom = drainCharBufferIntoAtom(anyCharsAccess().cx);
|
JSAtom* atom = drainCharBufferIntoAtom();
|
||||||
if (!atom) {
|
if (!atom) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1537,8 +1537,22 @@ class TokenStreamCharsShared {
|
||||||
return mozilla::IsAscii(static_cast<char32_t>(unit));
|
return mozilla::IsAscii(static_cast<char32_t>(unit));
|
||||||
}
|
}
|
||||||
|
|
||||||
JSAtom* drainCharBufferIntoAtom(JSContext* cx) {
|
JSAtom* drainCharBufferIntoAtom() {
|
||||||
JSAtom* atom = AtomizeChars(cx, charBuffer.begin(), charBuffer.length());
|
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();
|
charBuffer.clear();
|
||||||
return atom;
|
return atom;
|
||||||
}
|
}
|
||||||
|
@ -1602,8 +1616,7 @@ class TokenStreamCharsBase : public TokenStreamCharsShared {
|
||||||
sourceUnits.ungetCodeUnit();
|
sourceUnits.ungetCodeUnit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static MOZ_ALWAYS_INLINE JSAtom* atomizeSourceChars(
|
MOZ_ALWAYS_INLINE JSAtom* atomizeSourceChars(mozilla::Span<const Unit> units);
|
||||||
JSContext* cx, mozilla::Span<const Unit> units);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to match a non-LineTerminator ASCII code point. Return true iff it
|
* 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 <>
|
template <>
|
||||||
/* static */ MOZ_ALWAYS_INLINE JSAtom*
|
MOZ_ALWAYS_INLINE JSAtom* TokenStreamCharsBase<char16_t>::atomizeSourceChars(
|
||||||
TokenStreamCharsBase<char16_t>::atomizeSourceChars(
|
mozilla::Span<const char16_t> units) {
|
||||||
JSContext* cx, mozilla::Span<const char16_t> units) {
|
JSAtom* atom =
|
||||||
return AtomizeChars(cx, units.data(), units.size());
|
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 <>
|
template <>
|
||||||
/* static */ MOZ_ALWAYS_INLINE JSAtom*
|
/* static */ MOZ_ALWAYS_INLINE JSAtom*
|
||||||
TokenStreamCharsBase<mozilla::Utf8Unit>::atomizeSourceChars(
|
TokenStreamCharsBase<mozilla::Utf8Unit>::atomizeSourceChars(
|
||||||
JSContext* cx, mozilla::Span<const mozilla::Utf8Unit> units) {
|
mozilla::Span<const mozilla::Utf8Unit> units) {
|
||||||
auto chars = ToCharSpan(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>
|
template <typename Unit>
|
||||||
|
@ -2141,7 +2181,7 @@ class GeneralTokenStreamChars : public SpecializedTokenStreamCharsBase<Unit> {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return drainCharBufferIntoAtom(anyChars.cx);
|
return drainCharBufferIntoAtom();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ UNIFIED_SOURCES += [
|
||||||
'ParseContext.cpp',
|
'ParseContext.cpp',
|
||||||
'ParseNode.cpp',
|
'ParseNode.cpp',
|
||||||
'ParseNodeVerify.cpp',
|
'ParseNodeVerify.cpp',
|
||||||
|
'ParserAtom.cpp',
|
||||||
'PropOpEmitter.cpp',
|
'PropOpEmitter.cpp',
|
||||||
'SharedContext.cpp',
|
'SharedContext.cpp',
|
||||||
'SourceNotes.cpp',
|
'SourceNotes.cpp',
|
||||||
|
|
|
@ -464,6 +464,10 @@ JS_PUBLIC_API bool JS::InitSelfHostedCode(JSContext* cx) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!rt->initializeParserAtoms(cx)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef JS_CODEGEN_NONE
|
#ifndef JS_CODEGEN_NONE
|
||||||
if (!rt->createJitRuntime(cx)) {
|
if (!rt->createJitRuntime(cx)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1661,8 +1661,8 @@ bool JS_FASTCALL js::NumberValueToStringBuffer(JSContext* cx, const Value& v,
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename CharT>
|
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) {
|
double* result) {
|
||||||
if (length == 1) {
|
if (length == 1) {
|
||||||
CharT c = chars[0];
|
CharT c = chars[0];
|
||||||
if ('0' <= c && c <= '9') {
|
if ('0' <= c && c <= '9') {
|
||||||
|
@ -1731,6 +1731,16 @@ static bool CharsToNumber(JSContext* cx, const CharT* chars, size_t length,
|
||||||
return true;
|
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) {
|
bool js::StringToNumber(JSContext* cx, JSString* str, double* result) {
|
||||||
AutoCheckCannotGC nogc;
|
AutoCheckCannotGC nogc;
|
||||||
JSLinearString* linearStr = str->ensureLinear(cx);
|
JSLinearString* linearStr = str->ensureLinear(cx);
|
||||||
|
|
|
@ -176,6 +176,11 @@ template <typename CharT>
|
||||||
extern MOZ_MUST_USE bool GetDecimalNonInteger(JSContext* cx, const CharT* start,
|
extern MOZ_MUST_USE bool GetDecimalNonInteger(JSContext* cx, const CharT* start,
|
||||||
const CharT* end, double* dp);
|
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,
|
extern MOZ_MUST_USE bool StringToNumber(JSContext* cx, JSString* str,
|
||||||
double* result);
|
double* result);
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,19 @@ UniqueChars js::DuplicateStringToArena(arena_id_t destArenaId, JSContext* cx,
|
||||||
return ret;
|
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,
|
UniqueTwoByteChars js::DuplicateStringToArena(arena_id_t destArenaId,
|
||||||
JSContext* cx,
|
JSContext* cx,
|
||||||
const char16_t* s) {
|
const char16_t* s) {
|
||||||
|
@ -106,6 +119,19 @@ UniqueChars js::DuplicateStringToArena(arena_id_t destArenaId, const char* s,
|
||||||
return ret;
|
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,
|
UniqueTwoByteChars js::DuplicateStringToArena(arena_id_t destArenaId,
|
||||||
const char16_t* s) {
|
const char16_t* s) {
|
||||||
return DuplicateStringToArena(destArenaId, s, js_strlen(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);
|
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) {
|
UniqueTwoByteChars js::DuplicateString(JSContext* cx, const char16_t* s) {
|
||||||
return DuplicateStringToArena(js::MallocArena, cx, 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);
|
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) {
|
UniqueTwoByteChars js::DuplicateString(const char16_t* s) {
|
||||||
return DuplicateStringToArena(js::MallocArena, 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,
|
extern UniqueChars DuplicateStringToArena(arena_id_t destArenaId, JSContext* cx,
|
||||||
const char* s, size_t n);
|
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,
|
extern UniqueTwoByteChars DuplicateStringToArena(arena_id_t destArenaId,
|
||||||
JSContext* cx,
|
JSContext* cx,
|
||||||
const char16_t* s);
|
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,
|
extern UniqueChars DuplicateStringToArena(arena_id_t destArenaId, const char* s,
|
||||||
size_t n);
|
size_t n);
|
||||||
|
|
||||||
|
extern UniqueLatin1Chars DuplicateStringToArena(arena_id_t destArenaId,
|
||||||
|
const JS::Latin1Char* s,
|
||||||
|
size_t n);
|
||||||
|
|
||||||
extern UniqueTwoByteChars DuplicateStringToArena(arena_id_t destArenaId,
|
extern UniqueTwoByteChars DuplicateStringToArena(arena_id_t destArenaId,
|
||||||
const char16_t* s);
|
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 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);
|
||||||
|
|
||||||
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 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);
|
||||||
|
|
||||||
extern UniqueTwoByteChars DuplicateString(const char16_t* s, size_t n);
|
extern UniqueTwoByteChars DuplicateString(const char16_t* s, size_t n);
|
||||||
|
|
|
@ -40,6 +40,10 @@ class AutoAllocInAtomsZone;
|
||||||
class AutoMaybeLeaveAtomsZone;
|
class AutoMaybeLeaveAtomsZone;
|
||||||
class AutoRealm;
|
class AutoRealm;
|
||||||
|
|
||||||
|
namespace frontend {
|
||||||
|
class WellKnownParserAtoms;
|
||||||
|
} // namespace frontend
|
||||||
|
|
||||||
namespace jit {
|
namespace jit {
|
||||||
class JitActivation;
|
class JitActivation;
|
||||||
class JitContext;
|
class JitContext;
|
||||||
|
@ -265,6 +269,9 @@ struct JS_PUBLIC_API JSContext : public JS::RootingContext,
|
||||||
|
|
||||||
// Accessors for immutable runtime data.
|
// Accessors for immutable runtime data.
|
||||||
JSAtomState& names() { return *runtime_->commonNames; }
|
JSAtomState& names() { return *runtime_->commonNames; }
|
||||||
|
js::frontend::WellKnownParserAtoms& parserNames() {
|
||||||
|
return *runtime_->commonParserNames;
|
||||||
|
}
|
||||||
js::StaticStrings& staticStrings() { return *runtime_->staticStrings; }
|
js::StaticStrings& staticStrings() { return *runtime_->staticStrings; }
|
||||||
js::SharedImmutableStringsCache& sharedImmutableStrings() {
|
js::SharedImmutableStringsCache& sharedImmutableStrings() {
|
||||||
return runtime_->sharedImmutableStrings();
|
return runtime_->sharedImmutableStrings();
|
||||||
|
|
|
@ -109,6 +109,10 @@ class Simulator;
|
||||||
#endif
|
#endif
|
||||||
} // namespace jit
|
} // namespace jit
|
||||||
|
|
||||||
|
namespace frontend {
|
||||||
|
class WellKnownParserAtoms;
|
||||||
|
} // namespace frontend
|
||||||
|
|
||||||
// [SMDOC] JS Engine Threading
|
// [SMDOC] JS Engine Threading
|
||||||
//
|
//
|
||||||
// Threads interacting with a runtime are divided into two categories:
|
// Threads interacting with a runtime are divided into two categories:
|
||||||
|
@ -742,7 +746,9 @@ struct JSRuntime {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool initializeAtoms(JSContext* cx);
|
bool initializeAtoms(JSContext* cx);
|
||||||
|
bool initializeParserAtoms(JSContext* cx);
|
||||||
void finishAtoms();
|
void finishAtoms();
|
||||||
|
void finishParserAtoms();
|
||||||
bool atomsAreFinished() const {
|
bool atomsAreFinished() const {
|
||||||
return !atoms_ && !permanentAtomsDuringInit_;
|
return !atoms_ && !permanentAtomsDuringInit_;
|
||||||
}
|
}
|
||||||
|
@ -783,6 +789,7 @@ struct JSRuntime {
|
||||||
|
|
||||||
// Cached pointers to various permanent property names.
|
// Cached pointers to various permanent property names.
|
||||||
js::WriteOnceData<JSAtomState*> commonNames;
|
js::WriteOnceData<JSAtomState*> commonNames;
|
||||||
|
js::WriteOnceData<js::frontend::WellKnownParserAtoms*> commonParserNames;
|
||||||
|
|
||||||
// All permanent atoms in the runtime, other than those in staticStrings.
|
// 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
|
// 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>
|
template <typename CharT>
|
||||||
/* static */
|
bool js::CheckStringIsIndex(const CharT* s, size_t length, uint32_t* indexp) {
|
||||||
bool JSLinearString::isIndexSlow(const CharT* s, size_t length,
|
|
||||||
uint32_t* indexp) {
|
|
||||||
MOZ_ASSERT(length > 0);
|
MOZ_ASSERT(length > 0);
|
||||||
MOZ_ASSERT(length <= UINT32_CHAR_BUFFER_LENGTH);
|
MOZ_ASSERT(length <= UINT32_CHAR_BUFFER_LENGTH);
|
||||||
MOZ_ASSERT(IsAsciiDigit(*s),
|
MOZ_ASSERT(IsAsciiDigit(*s),
|
||||||
|
@ -1194,6 +1192,18 @@ bool JSLinearString::isIndexSlow(const CharT* s, size_t length,
|
||||||
return false;
|
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,
|
template bool JSLinearString::isIndexSlow(const Latin1Char* s, size_t length,
|
||||||
uint32_t* indexp);
|
uint32_t* indexp);
|
||||||
|
|
||||||
|
|
|
@ -1259,6 +1259,9 @@ MOZ_ALWAYS_INLINE JSAtom* JSLinearString::morphAtomizedStringIntoPermanentAtom(
|
||||||
|
|
||||||
namespace js {
|
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
|
* An indexable characters class exposing unaligned, little-endian encoded
|
||||||
* char16_t data.
|
* char16_t data.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче