mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-15 08:53:07 +09:00
Merge remote-tracking branch 'origin/tracking' into custom
This commit is contained in:
commit
85f6a49297
19 changed files with 347 additions and 170 deletions
|
|
@ -278,6 +278,7 @@ def old_configure_options(*options):
|
|||
'--with-ios-sdk',
|
||||
'--with-jitreport-granularity',
|
||||
'--with-macbundlename-prefix',
|
||||
'--with-macbundle-identity',
|
||||
'--with-macos-private-frameworks',
|
||||
'--with-macos-sdk',
|
||||
'--with-nspr-cflags',
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
/* Implementation of the Intl.PluralRules proposal. */
|
||||
|
||||
#include "builtin/intl/NumberFormat.h"
|
||||
#include "builtin/intl/PluralRules.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "jsatom.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsstr.h"
|
||||
|
||||
#include "builtin/intl/CommonFunctions.h"
|
||||
|
|
|
|||
|
|
@ -63,10 +63,11 @@ using namespace js::jit;
|
|||
* The tempN registers are free to use for computations.
|
||||
*/
|
||||
|
||||
NativeRegExpMacroAssembler::NativeRegExpMacroAssembler(JSContext* cx, LifoAlloc* alloc, RegExpShared* shared,
|
||||
JSRuntime* rt, Mode mode, int registers_to_save)
|
||||
: RegExpMacroAssembler(cx, *alloc, shared, registers_to_save),
|
||||
cx(cx), runtime(rt), mode_(mode)
|
||||
NativeRegExpMacroAssembler::NativeRegExpMacroAssembler(LifoAlloc* alloc, JSRuntime* rt,
|
||||
Mode mode, int registers_to_save,
|
||||
RegExpShared::JitCodeTables& tables)
|
||||
: RegExpMacroAssembler(*alloc, registers_to_save),
|
||||
tables(tables), runtime(rt), mode_(mode)
|
||||
{
|
||||
// Find physical registers for each compiler register.
|
||||
AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
|
||||
|
|
@ -886,11 +887,11 @@ NativeRegExpMacroAssembler::CheckCharacterNotInRange(char16_t from, char16_t to,
|
|||
}
|
||||
|
||||
void
|
||||
NativeRegExpMacroAssembler::CheckBitInTable(uint8_t* table, Label* on_bit_set)
|
||||
NativeRegExpMacroAssembler::CheckBitInTable(RegExpShared::JitCodeTable table, Label* on_bit_set)
|
||||
{
|
||||
JitSpew(SPEW_PREFIX "CheckBitInTable");
|
||||
|
||||
masm.movePtr(ImmPtr(table), temp0);
|
||||
masm.movePtr(ImmPtr(table.get()), temp0);
|
||||
|
||||
// kTableMask is currently 127, so we need to mask even if the input is
|
||||
// Latin1. V8 has the same issue.
|
||||
|
|
@ -901,6 +902,13 @@ NativeRegExpMacroAssembler::CheckBitInTable(uint8_t* table, Label* on_bit_set)
|
|||
|
||||
masm.load8ZeroExtend(BaseIndex(temp0, temp1, TimesOne), temp0);
|
||||
masm.branchTest32(Assembler::NonZero, temp0, temp0, BranchOrBacktrack(on_bit_set));
|
||||
|
||||
// Transfer ownership of |table| to the |tables| Vector.
|
||||
{
|
||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
||||
if (!tables.append(Move(table)))
|
||||
oomUnsafe.crash("RegExp table append");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -87,8 +87,8 @@ class MOZ_STACK_CLASS NativeRegExpMacroAssembler final : public RegExpMacroAssem
|
|||
// Type of input string to generate code for.
|
||||
enum Mode { ASCII = 1, CHAR16 = 2 };
|
||||
|
||||
NativeRegExpMacroAssembler(JSContext* cx, LifoAlloc* alloc, RegExpShared* shared,
|
||||
JSRuntime* rt, Mode mode, int registers_to_save);
|
||||
NativeRegExpMacroAssembler(LifoAlloc* alloc, JSRuntime* rt, Mode mode, int registers_to_save,
|
||||
RegExpShared::JitCodeTables& tables);
|
||||
|
||||
// Inherited virtual methods.
|
||||
RegExpCode GenerateCode(JSContext* cx, bool match_only);
|
||||
|
|
@ -116,7 +116,7 @@ class MOZ_STACK_CLASS NativeRegExpMacroAssembler final : public RegExpMacroAssem
|
|||
jit::Label* on_in_range);
|
||||
void CheckCharacterNotInRange(char16_t from, char16_t to,
|
||||
jit::Label* on_not_in_range);
|
||||
void CheckBitInTable(uint8_t* table, jit::Label* on_bit_set);
|
||||
void CheckBitInTable(RegExpShared::JitCodeTable table, jit::Label* on_bit_set);
|
||||
void CheckPosition(int cp_offset, jit::Label* on_outside_input);
|
||||
void JumpOrBacktrack(jit::Label* to);
|
||||
bool CheckSpecialCharacterClass(char16_t type, jit::Label* on_no_match);
|
||||
|
|
@ -173,8 +173,8 @@ class MOZ_STACK_CLASS NativeRegExpMacroAssembler final : public RegExpMacroAssem
|
|||
|
||||
private:
|
||||
jit::MacroAssembler masm;
|
||||
RegExpShared::JitCodeTables& tables;
|
||||
|
||||
JSContext* cx;
|
||||
JSRuntime* runtime;
|
||||
Mode mode_;
|
||||
jit::Label entry_label_;
|
||||
|
|
|
|||
|
|
@ -1262,7 +1262,7 @@ RegExpCode
|
|||
irregexp::CompilePattern(JSContext* cx, HandleRegExpShared shared, RegExpCompileData* data,
|
||||
HandleLinearString sample, bool is_global, bool ignore_case,
|
||||
bool is_ascii, bool match_only, bool force_bytecode, bool sticky,
|
||||
bool unicode)
|
||||
bool unicode, RegExpShared::JitCodeTables& tables)
|
||||
{
|
||||
if ((data->capture_count + 1) * 2 - 1 > RegExpMacroAssembler::kMaxRegister) {
|
||||
JS_ReportErrorASCII(cx, "regexp too big");
|
||||
|
|
@ -1350,10 +1350,10 @@ irregexp::CompilePattern(JSContext* cx, HandleRegExpShared shared, RegExpCompile
|
|||
: NativeRegExpMacroAssembler::CHAR16;
|
||||
|
||||
ctx.emplace(cx, (jit::TempAllocator*) nullptr);
|
||||
native_assembler.emplace(cx, &alloc, shared, cx->runtime(), mode, (data->capture_count + 1) * 2);
|
||||
native_assembler.emplace(&alloc, cx->runtime(), mode, (data->capture_count + 1) * 2, tables);
|
||||
assembler = native_assembler.ptr();
|
||||
} else {
|
||||
interpreted_assembler.emplace(cx, &alloc, shared, (data->capture_count + 1) * 2);
|
||||
interpreted_assembler.emplace(&alloc, (data->capture_count + 1) * 2);
|
||||
assembler = interpreted_assembler.ptr();
|
||||
}
|
||||
|
||||
|
|
@ -2040,21 +2040,21 @@ BoyerMooreLookahead::EmitSkipInstructions(RegExpMacroAssembler* masm)
|
|||
return true;
|
||||
}
|
||||
|
||||
uint8_t* boolean_skip_table;
|
||||
RegExpShared::JitCodeTable boolean_skip_table;
|
||||
{
|
||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
||||
boolean_skip_table = static_cast<uint8_t*>(js_malloc(kSize));
|
||||
if (!boolean_skip_table || !masm->shared->addTable(boolean_skip_table))
|
||||
boolean_skip_table.reset(static_cast<uint8_t*>(js_malloc(kSize)));
|
||||
if (!boolean_skip_table)
|
||||
oomUnsafe.crash("Table malloc");
|
||||
}
|
||||
|
||||
int skip_distance = GetSkipTable(min_lookahead, max_lookahead, boolean_skip_table);
|
||||
int skip_distance = GetSkipTable(min_lookahead, max_lookahead, boolean_skip_table.get());
|
||||
MOZ_ASSERT(skip_distance != 0);
|
||||
|
||||
jit::Label cont, again;
|
||||
masm->Bind(&again);
|
||||
masm->LoadCurrentCharacter(max_lookahead, &cont, true);
|
||||
masm->CheckBitInTable(boolean_skip_table, &cont);
|
||||
masm->CheckBitInTable(Move(boolean_skip_table), &cont);
|
||||
masm->AdvanceCurrentPosition(skip_distance);
|
||||
masm->JumpOrBacktrack(&again);
|
||||
masm->Bind(&cont);
|
||||
|
|
@ -2832,18 +2832,18 @@ EmitUseLookupTable(RegExpMacroAssembler* masm,
|
|||
}
|
||||
|
||||
// TODO(erikcorry): Cache these.
|
||||
uint8_t* ba;
|
||||
RegExpShared::JitCodeTable ba;
|
||||
{
|
||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
||||
ba = static_cast<uint8_t*>(js_malloc(kSize));
|
||||
if (!ba || !masm->shared->addTable(ba))
|
||||
ba.reset(static_cast<uint8_t*>(js_malloc(kSize)));
|
||||
if (!ba)
|
||||
oomUnsafe.crash("Table malloc");
|
||||
}
|
||||
|
||||
for (int i = 0; i < kSize; i++)
|
||||
ba[i] = templ[i];
|
||||
|
||||
masm->CheckBitInTable(ba, on_bit_set);
|
||||
masm->CheckBitInTable(Move(ba), on_bit_set);
|
||||
if (on_bit_clear != fall_through)
|
||||
masm->JumpOrBacktrack(on_bit_clear);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ RegExpCode
|
|||
CompilePattern(JSContext* cx, HandleRegExpShared shared, RegExpCompileData* data,
|
||||
HandleLinearString sample, bool is_global, bool ignore_case,
|
||||
bool is_ascii, bool match_only, bool force_bytecode, bool sticky,
|
||||
bool unicode);
|
||||
bool unicode, RegExpShared::JitCodeTables& tables);
|
||||
|
||||
// Note: this may return RegExpRunStatus_Error if an interrupt was requested
|
||||
// while the code was executing.
|
||||
|
|
|
|||
|
|
@ -96,10 +96,9 @@ irregexp::CaseInsensitiveCompareUCStrings(const char16_t* substring1,
|
|||
const char16_t* substring2,
|
||||
size_t byteLength);
|
||||
|
||||
InterpretedRegExpMacroAssembler::InterpretedRegExpMacroAssembler(JSContext* cx, LifoAlloc* alloc,
|
||||
RegExpShared* shared,
|
||||
InterpretedRegExpMacroAssembler::InterpretedRegExpMacroAssembler(LifoAlloc* alloc,
|
||||
size_t numSavedRegisters)
|
||||
: RegExpMacroAssembler(cx, *alloc, shared, numSavedRegisters),
|
||||
: RegExpMacroAssembler(*alloc, numSavedRegisters),
|
||||
pc_(0),
|
||||
advance_current_start_(0),
|
||||
advance_current_offset_(0),
|
||||
|
|
@ -317,7 +316,8 @@ InterpretedRegExpMacroAssembler::CheckCharacterNotInRange(char16_t from, char16_
|
|||
}
|
||||
|
||||
void
|
||||
InterpretedRegExpMacroAssembler::CheckBitInTable(uint8_t* table, jit::Label* on_bit_set)
|
||||
InterpretedRegExpMacroAssembler::CheckBitInTable(RegExpShared::JitCodeTable table,
|
||||
jit::Label* on_bit_set)
|
||||
{
|
||||
static const int kBitsPerByte = 8;
|
||||
|
||||
|
|
|
|||
|
|
@ -40,14 +40,12 @@ namespace irregexp {
|
|||
class MOZ_STACK_CLASS RegExpMacroAssembler
|
||||
{
|
||||
public:
|
||||
RegExpMacroAssembler(JSContext* cx, LifoAlloc& alloc, RegExpShared* shared,
|
||||
size_t numSavedRegisters)
|
||||
RegExpMacroAssembler(LifoAlloc& alloc, size_t numSavedRegisters)
|
||||
: slow_safe_compiler_(false),
|
||||
global_mode_(NOT_GLOBAL),
|
||||
alloc_(alloc),
|
||||
num_registers_(numSavedRegisters),
|
||||
num_saved_registers_(numSavedRegisters),
|
||||
shared(cx, shared)
|
||||
num_saved_registers_(numSavedRegisters)
|
||||
{}
|
||||
|
||||
enum StackCheckFlag {
|
||||
|
|
@ -137,7 +135,7 @@ class MOZ_STACK_CLASS RegExpMacroAssembler
|
|||
|
||||
// The current character (modulus the kTableSize) is looked up in the byte
|
||||
// array, and if the found byte is non-zero, we jump to the on_bit_set label.
|
||||
virtual void CheckBitInTable(uint8_t* table, jit::Label* on_bit_set) = 0;
|
||||
virtual void CheckBitInTable(RegExpShared::JitCodeTable table, jit::Label* on_bit_set) = 0;
|
||||
|
||||
// Checks whether the given offset from the current position is before
|
||||
// the end of the string. May overwrite the current character.
|
||||
|
|
@ -213,9 +211,6 @@ class MOZ_STACK_CLASS RegExpMacroAssembler
|
|||
if (num_registers_ <= reg)
|
||||
num_registers_ = reg + 1;
|
||||
}
|
||||
|
||||
public:
|
||||
RootedRegExpShared shared;
|
||||
};
|
||||
|
||||
template <typename CharT>
|
||||
|
|
@ -230,8 +225,7 @@ CaseInsensitiveCompareUCStrings(const CharT* substring1, const CharT* substring2
|
|||
class MOZ_STACK_CLASS InterpretedRegExpMacroAssembler final : public RegExpMacroAssembler
|
||||
{
|
||||
public:
|
||||
InterpretedRegExpMacroAssembler(JSContext* cx, LifoAlloc* alloc, RegExpShared* shared,
|
||||
size_t numSavedRegisters);
|
||||
InterpretedRegExpMacroAssembler(LifoAlloc* alloc, size_t numSavedRegisters);
|
||||
~InterpretedRegExpMacroAssembler();
|
||||
|
||||
// Inherited virtual methods.
|
||||
|
|
@ -258,7 +252,7 @@ class MOZ_STACK_CLASS InterpretedRegExpMacroAssembler final : public RegExpMacro
|
|||
jit::Label* on_in_range);
|
||||
void CheckCharacterNotInRange(char16_t from, char16_t to,
|
||||
jit::Label* on_not_in_range);
|
||||
void CheckBitInTable(uint8_t* table, jit::Label* on_bit_set);
|
||||
void CheckBitInTable(RegExpShared::JitCodeTable table, jit::Label* on_bit_set);
|
||||
void JumpOrBacktrack(jit::Label* to);
|
||||
void Fail();
|
||||
void IfRegisterGE(int reg, int comparand, jit::Label* if_ge);
|
||||
|
|
|
|||
|
|
@ -46,7 +46,8 @@ struct LoopIterationBound : public TempObject
|
|||
// of the loop header. This will use loop invariant terms and header phis.
|
||||
LinearSum currentSum;
|
||||
|
||||
LoopIterationBound(MBasicBlock* header, MTest* test, LinearSum boundSum, LinearSum currentSum)
|
||||
LoopIterationBound(MBasicBlock* header, MTest* test,
|
||||
const LinearSum& boundSum, const LinearSum& currentSum)
|
||||
: header(header), test(test),
|
||||
boundSum(boundSum), currentSum(currentSum)
|
||||
{
|
||||
|
|
@ -59,7 +60,7 @@ typedef Vector<LoopIterationBound*, 0, SystemAllocPolicy> LoopIterationBoundVect
|
|||
struct SymbolicBound : public TempObject
|
||||
{
|
||||
private:
|
||||
SymbolicBound(LoopIterationBound* loop, LinearSum sum)
|
||||
SymbolicBound(LoopIterationBound* loop, const LinearSum& sum)
|
||||
: loop(loop), sum(sum)
|
||||
{
|
||||
}
|
||||
|
|
@ -73,7 +74,8 @@ struct SymbolicBound : public TempObject
|
|||
// If nullptr, then 'sum' is always valid.
|
||||
LoopIterationBound* loop;
|
||||
|
||||
static SymbolicBound* New(TempAllocator& alloc, LoopIterationBound* loop, LinearSum sum) {
|
||||
static SymbolicBound*
|
||||
New(TempAllocator& alloc, LoopIterationBound* loop, const LinearSum& sum) {
|
||||
return new(alloc) SymbolicBound(loop, sum);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
/* Note: Aborts on OOM. */
|
||||
class JSAPITestString {
|
||||
js::Vector<char, 0, js::SystemAllocPolicy> chars;
|
||||
|
||||
public:
|
||||
JSAPITestString() {}
|
||||
explicit JSAPITestString(const char* s) { *this += s; }
|
||||
|
|
@ -32,21 +33,34 @@ class JSAPITestString {
|
|||
const char* end() const { return chars.end(); }
|
||||
size_t length() const { return chars.length(); }
|
||||
|
||||
JSAPITestString & operator +=(const char* s) {
|
||||
JSAPITestString& operator +=(const char* s) {
|
||||
if (!chars.append(s, strlen(s)))
|
||||
abort();
|
||||
return *this;
|
||||
}
|
||||
|
||||
JSAPITestString & operator +=(const JSAPITestString& s) {
|
||||
JSAPITestString& operator +=(const JSAPITestString& s) {
|
||||
if (!chars.append(s.begin(), s.length()))
|
||||
abort();
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
inline JSAPITestString operator+(JSAPITestString a, const char* b) { return a += b; }
|
||||
inline JSAPITestString operator+(JSAPITestString a, const JSAPITestString& b) { return a += b; }
|
||||
inline JSAPITestString
|
||||
operator+(const JSAPITestString& a, const char* b)
|
||||
{
|
||||
JSAPITestString result = a;
|
||||
result += b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline JSAPITestString
|
||||
operator+(const JSAPITestString& a, const JSAPITestString& b)
|
||||
{
|
||||
JSAPITestString result = a;
|
||||
result += b;
|
||||
return result;
|
||||
}
|
||||
|
||||
class JSAPITest
|
||||
{
|
||||
|
|
@ -205,7 +219,11 @@ class JSAPITest
|
|||
return fail(JSAPITestString("CHECK failed: " #expr), __FILE__, __LINE__); \
|
||||
} while (false)
|
||||
|
||||
bool fail(JSAPITestString msg = JSAPITestString(), const char* filename = "-", int lineno = 0) {
|
||||
bool fail(const JSAPITestString& msg = JSAPITestString(),
|
||||
const char* filename = "-",
|
||||
int lineno = 0)
|
||||
{
|
||||
JSAPITestString message = msg;
|
||||
if (JS_IsExceptionPending(cx)) {
|
||||
js::gc::AutoSuppressGC gcoff(cx);
|
||||
JS::RootedValue v(cx);
|
||||
|
|
@ -215,11 +233,12 @@ class JSAPITest
|
|||
if (s) {
|
||||
JSAutoByteString bytes(cx, s);
|
||||
if (!!bytes)
|
||||
msg += bytes.ptr();
|
||||
message += bytes.ptr();
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "%s:%d:%.*s\n", filename, lineno, (int) msg.length(), msg.begin());
|
||||
msgs += msg;
|
||||
fprintf(stderr, "%s:%d:%.*s\n",
|
||||
filename, lineno, int(message.length()), message.begin());
|
||||
msgs += message;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -187,11 +187,6 @@ IsMarkingTrace(JSTracer* trc)
|
|||
void
|
||||
RegExpObject::trace(JSTracer* trc)
|
||||
{
|
||||
// When marking the object normally we have the option of unlinking the
|
||||
// object from its RegExpShared so that the RegExpShared may be collected.
|
||||
if (IsMarkingTrace(trc) && !zone()->isPreservingCode())
|
||||
sharedRef() = nullptr;
|
||||
|
||||
TraceNullableEdge(trc, &sharedRef(), "RegExpObject shared");
|
||||
}
|
||||
|
||||
|
|
@ -970,6 +965,9 @@ RegExpShared::discardJitCode()
|
|||
{
|
||||
for (auto& comp : compilationArray)
|
||||
comp.jitCode = nullptr;
|
||||
|
||||
// We can also purge the tables used by JIT code.
|
||||
tables.clearAndFree();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -977,8 +975,6 @@ RegExpShared::finalize(FreeOp* fop)
|
|||
{
|
||||
for (auto& comp : compilationArray)
|
||||
js_free(comp.byteCode);
|
||||
for (size_t i = 0; i < tables.length(); i++)
|
||||
js_free(tables[i]);
|
||||
tables.~JitCodeTables();
|
||||
}
|
||||
|
||||
|
|
@ -1075,6 +1071,7 @@ RegExpShared::compile(JSContext* cx, MutableHandleRegExpShared re, HandleAtom pa
|
|||
}
|
||||
}
|
||||
|
||||
JitCodeTables tables;
|
||||
irregexp::RegExpCode code = irregexp::CompilePattern(cx, re, &data, input,
|
||||
false /* global() */,
|
||||
re->ignoreCase(),
|
||||
|
|
@ -1082,7 +1079,8 @@ RegExpShared::compile(JSContext* cx, MutableHandleRegExpShared re, HandleAtom pa
|
|||
mode == MatchOnly,
|
||||
force == ForceByteCode,
|
||||
re->sticky(),
|
||||
re->unicode());
|
||||
re->unicode(),
|
||||
tables);
|
||||
if (code.empty())
|
||||
return false;
|
||||
|
||||
|
|
@ -1090,10 +1088,20 @@ RegExpShared::compile(JSContext* cx, MutableHandleRegExpShared re, HandleAtom pa
|
|||
MOZ_ASSERT_IF(force == ForceByteCode, code.byteCode);
|
||||
|
||||
RegExpCompilation& compilation = re->compilation(mode, input->hasLatin1Chars());
|
||||
if (code.jitCode)
|
||||
if (code.jitCode) {
|
||||
// First copy the tables. GC can purge the tables if the RegExpShared
|
||||
// has no JIT code, so it's important to do this right before setting
|
||||
// compilation.jitCode (to ensure no purging happens between adding the
|
||||
// tables and setting the JIT code).
|
||||
for (size_t i = 0; i < tables.length(); i++) {
|
||||
if (!re->addTable(Move(tables[i])))
|
||||
return false;
|
||||
}
|
||||
compilation.jitCode = code.jitCode;
|
||||
else if (code.byteCode)
|
||||
} else if (code.byteCode) {
|
||||
MOZ_ASSERT(tables.empty(), "RegExpInterpreter does not use data tables");
|
||||
compilation.byteCode = code.byteCode;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1249,7 +1257,7 @@ RegExpShared::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
|||
|
||||
n += tables.sizeOfExcludingThis(mallocSizeOf);
|
||||
for (size_t i = 0; i < tables.length(); i++)
|
||||
n += mallocSizeOf(tables[i]);
|
||||
n += mallocSizeOf(tables[i].get());
|
||||
|
||||
return n;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,9 @@ class RegExpShared : public gc::TenuredCell
|
|||
ForceByteCode
|
||||
};
|
||||
|
||||
using JitCodeTable = UniquePtr<uint8_t[], JS::FreePolicy>;
|
||||
using JitCodeTables = Vector<JitCodeTable, 0, SystemAllocPolicy>;
|
||||
|
||||
private:
|
||||
friend class RegExpCompartment;
|
||||
friend class RegExpStatics;
|
||||
|
|
@ -148,7 +151,6 @@ class RegExpShared : public gc::TenuredCell
|
|||
}
|
||||
|
||||
// Tables referenced by JIT code.
|
||||
using JitCodeTables = Vector<uint8_t*, 0, SystemAllocPolicy>;
|
||||
JitCodeTables tables;
|
||||
|
||||
/* Internal functions. */
|
||||
|
|
@ -181,8 +183,8 @@ class RegExpShared : public gc::TenuredCell
|
|||
MatchPairs* matches, size_t* endIndex);
|
||||
|
||||
// Register a table with this RegExpShared, and take ownership.
|
||||
bool addTable(uint8_t* table) {
|
||||
return tables.append(table);
|
||||
bool addTable(JitCodeTable table) {
|
||||
return tables.append(Move(table));
|
||||
}
|
||||
|
||||
/* Accessors */
|
||||
|
|
@ -464,7 +466,7 @@ class RegExpObject : public NativeObject
|
|||
|
||||
void setShared(RegExpShared& shared) {
|
||||
MOZ_ASSERT(!hasShared());
|
||||
sharedRef() = &shared;
|
||||
sharedRef().init(&shared);
|
||||
}
|
||||
|
||||
static void trace(JSTracer* trc, JSObject* obj);
|
||||
|
|
@ -490,9 +492,9 @@ class RegExpObject : public NativeObject
|
|||
static MOZ_MUST_USE bool createShared(JSContext* cx, Handle<RegExpObject*> regexp,
|
||||
MutableHandleRegExpShared shared);
|
||||
|
||||
ReadBarriered<RegExpShared*>& sharedRef() {
|
||||
PreBarriered<RegExpShared*>& sharedRef() {
|
||||
auto& ref = NativeObject::privateRef(PRIVATE_SLOT);
|
||||
return reinterpret_cast<ReadBarriered<RegExpShared*>&>(ref);
|
||||
return reinterpret_cast<PreBarriered<RegExpShared*>&>(ref);
|
||||
}
|
||||
|
||||
/* Call setShared in preference to setPrivate. */
|
||||
|
|
|
|||
278
mfbt/Vector.h
278
mfbt/Vector.h
|
|
@ -146,7 +146,7 @@ struct VectorImpl
|
|||
aV.free_(aV.mBegin);
|
||||
aV.mBegin = newbuf;
|
||||
/* aV.mLength is unchanged. */
|
||||
aV.mCapacity = aNewCap;
|
||||
aV.mTail.mCapacity = aNewCap;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
@ -225,28 +225,30 @@ struct VectorImpl<T, N, AP, true>
|
|||
{
|
||||
MOZ_ASSERT(!aV.usingInlineStorage());
|
||||
MOZ_ASSERT(!CapacityHasExcessSpace<T>(aNewCap));
|
||||
T* newbuf = aV.template pod_realloc<T>(aV.mBegin, aV.mCapacity, aNewCap);
|
||||
T* newbuf =
|
||||
aV.template pod_realloc<T>(aV.mBegin, aV.mTail.mCapacity, aNewCap);
|
||||
if (MOZ_UNLIKELY(!newbuf)) {
|
||||
return false;
|
||||
}
|
||||
aV.mBegin = newbuf;
|
||||
/* aV.mLength is unchanged. */
|
||||
aV.mCapacity = aNewCap;
|
||||
aV.mTail.mCapacity = aNewCap;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void
|
||||
podResizeToFit(Vector<T, N, AP>& aV)
|
||||
{
|
||||
if (aV.usingInlineStorage() || aV.mLength == aV.mCapacity) {
|
||||
if (aV.usingInlineStorage() || aV.mLength == aV.mTail.mCapacity) {
|
||||
return;
|
||||
}
|
||||
T* newbuf = aV.template pod_realloc<T>(aV.mBegin, aV.mCapacity, aV.mLength);
|
||||
T* newbuf =
|
||||
aV.template pod_realloc<T>(aV.mBegin, aV.mTail.mCapacity, aV.mLength);
|
||||
if (MOZ_UNLIKELY(!newbuf)) {
|
||||
return;
|
||||
}
|
||||
aV.mBegin = newbuf;
|
||||
aV.mCapacity = aV.mLength;
|
||||
aV.mTail.mCapacity = aV.mLength;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -277,7 +279,7 @@ struct VectorTesting;
|
|||
template<typename T,
|
||||
size_t MinInlineCapacity = 0,
|
||||
class AllocPolicy = MallocAllocPolicy>
|
||||
class Vector final : private AllocPolicy
|
||||
class MOZ_NON_PARAM Vector final : private AllocPolicy
|
||||
{
|
||||
/* utilities */
|
||||
|
||||
|
|
@ -293,36 +295,39 @@ class Vector final : private AllocPolicy
|
|||
|
||||
/* magic constants */
|
||||
|
||||
static const int kMaxInlineBytes = 1024;
|
||||
|
||||
/* compute constants */
|
||||
|
||||
/*
|
||||
* Consider element size to be 1 for buffer sizing if there are 0 inline
|
||||
* elements. This allows us to compile when the definition of the element
|
||||
* type is not visible here.
|
||||
/**
|
||||
* The maximum space allocated for inline element storage.
|
||||
*
|
||||
* Explicit specialization is only allowed at namespace scope, so in order
|
||||
* to keep everything here, we use a dummy template parameter with partial
|
||||
* specialization.
|
||||
* We reduce space by what the AllocPolicy base class and prior Vector member
|
||||
* fields likely consume to attempt to play well with binary size classes.
|
||||
*/
|
||||
template<int M, int Dummy>
|
||||
struct ElemSize
|
||||
{
|
||||
static const size_t value = sizeof(T);
|
||||
};
|
||||
template<int Dummy>
|
||||
struct ElemSize<0, Dummy>
|
||||
{
|
||||
static const size_t value = 1;
|
||||
static constexpr size_t kMaxInlineBytes =
|
||||
1024 -
|
||||
(sizeof(AllocPolicy) + sizeof(T*) + sizeof(size_t) + sizeof(size_t));
|
||||
|
||||
/**
|
||||
* The number of T elements of inline capacity built into this Vector. This
|
||||
* is usually |MinInlineCapacity|, but it may be less (or zero!) for large T.
|
||||
*
|
||||
* We use a partially-specialized template (not explicit specialization, which
|
||||
* is only allowed at namespace scope) to compute this value. The benefit is
|
||||
* that |sizeof(T)| need not be computed, and |T| doesn't have to be fully
|
||||
* defined at the time |Vector<T>| appears, if no inline storage is requested.
|
||||
*/
|
||||
template <size_t MinimumInlineCapacity, size_t Dummy>
|
||||
struct ComputeCapacity {
|
||||
static constexpr size_t value =
|
||||
tl::Min<MinimumInlineCapacity, kMaxInlineBytes / sizeof(T)>::value;
|
||||
};
|
||||
|
||||
static const size_t kInlineCapacity =
|
||||
tl::Min<MinInlineCapacity, kMaxInlineBytes / ElemSize<MinInlineCapacity, 0>::value>::value;
|
||||
template <size_t Dummy>
|
||||
struct ComputeCapacity<0, Dummy> {
|
||||
static constexpr size_t value = 0;
|
||||
};
|
||||
|
||||
/* Calculate inline buffer size; avoid 0-sized array. */
|
||||
static const size_t kInlineBytes =
|
||||
tl::Max<1, kInlineCapacity * ElemSize<MinInlineCapacity, 0>::value>::value;
|
||||
/** The actual inline capacity in number of elements T. This may be zero! */
|
||||
static constexpr size_t kInlineCapacity =
|
||||
ComputeCapacity<MinInlineCapacity, 0>::value;
|
||||
|
||||
/* member data */
|
||||
|
||||
|
|
@ -338,16 +343,84 @@ class Vector final : private AllocPolicy
|
|||
/* Number of elements in the vector. */
|
||||
size_t mLength;
|
||||
|
||||
/* Max number of elements storable in the vector without resizing. */
|
||||
size_t mCapacity;
|
||||
/*
|
||||
* Memory used to store capacity, reserved element count (debug builds only),
|
||||
* and inline storage. The simple "answer" is:
|
||||
*
|
||||
* size_t mCapacity;
|
||||
* #ifdef DEBUG
|
||||
* size_t mReserved;
|
||||
* #endif
|
||||
* alignas(T) unsigned char mBytes[kInlineCapacity * sizeof(T)];
|
||||
*
|
||||
* but there are complications. First, C++ forbids zero-sized arrays that
|
||||
* might result. Second, we don't want zero capacity to affect Vector's size
|
||||
* (even empty classes take up a byte, unless they're base classes).
|
||||
*
|
||||
* Yet again, we eliminate the zero-sized array using partial specialization.
|
||||
* And we eliminate potential size hit by putting capacity/reserved in one
|
||||
* struct, then putting the array (if any) in a derived struct. If no array
|
||||
* is needed, the derived struct won't consume extra space.
|
||||
*/
|
||||
struct CapacityAndReserved
|
||||
{
|
||||
explicit CapacityAndReserved(size_t aCapacity, size_t aReserved)
|
||||
: mCapacity(aCapacity)
|
||||
#ifdef DEBUG
|
||||
, mReserved(aReserved)
|
||||
#endif
|
||||
{}
|
||||
CapacityAndReserved() = default;
|
||||
|
||||
/* Max number of elements storable in the vector without resizing. */
|
||||
size_t mCapacity;
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Max elements of reserved or used space in this vector. */
|
||||
size_t mReserved;
|
||||
/* Max elements of reserved or used space in this vector. */
|
||||
size_t mReserved;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Memory used for inline storage. */
|
||||
AlignedStorage<kInlineBytes> mStorage;
|
||||
// Silence warnings about this struct possibly being padded dued to the
|
||||
// alignas() in it -- there's nothing we can do to avoid it.
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4324)
|
||||
#endif // _MSC_VER
|
||||
|
||||
template<size_t Capacity, size_t Dummy>
|
||||
struct CRAndStorage : CapacityAndReserved
|
||||
{
|
||||
explicit CRAndStorage(size_t aCapacity, size_t aReserved)
|
||||
: CapacityAndReserved(aCapacity, aReserved)
|
||||
{}
|
||||
CRAndStorage() = default;
|
||||
|
||||
alignas(T) unsigned char mBytes[Capacity * sizeof(T)];
|
||||
|
||||
// GCC fails due to -Werror=strict-aliasing if |mBytes| is directly cast to
|
||||
// T*. Indirecting through this function addresses the problem.
|
||||
void* data() { return mBytes; }
|
||||
|
||||
T* storage() { return static_cast<T*>(data()); }
|
||||
};
|
||||
|
||||
template<size_t Dummy>
|
||||
struct CRAndStorage<0, Dummy> : CapacityAndReserved
|
||||
{
|
||||
explicit CRAndStorage(size_t aCapacity, size_t aReserved)
|
||||
: CapacityAndReserved(aCapacity, aReserved)
|
||||
{}
|
||||
CRAndStorage() = default;
|
||||
|
||||
T* storage() { return nullptr; }
|
||||
};
|
||||
|
||||
CRAndStorage<kInlineCapacity, 0> mTail;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop)
|
||||
#endif // _MSC_VER
|
||||
|
||||
#ifdef DEBUG
|
||||
friend class ReentrancyGuard;
|
||||
|
|
@ -363,7 +436,7 @@ class Vector final : private AllocPolicy
|
|||
|
||||
T* inlineStorage()
|
||||
{
|
||||
return static_cast<T*>(mStorage.addr());
|
||||
return mTail.storage();
|
||||
}
|
||||
|
||||
T* beginNoCheck() const
|
||||
|
|
@ -391,9 +464,9 @@ class Vector final : private AllocPolicy
|
|||
*/
|
||||
size_t reserved() const
|
||||
{
|
||||
MOZ_ASSERT(mLength <= mReserved);
|
||||
MOZ_ASSERT(mReserved <= mCapacity);
|
||||
return mReserved;
|
||||
MOZ_ASSERT(mLength <= mTail.mReserved);
|
||||
MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity);
|
||||
return mTail.mReserved;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -426,7 +499,7 @@ public:
|
|||
|
||||
bool empty() const { return mLength == 0; }
|
||||
|
||||
size_t capacity() const { return mCapacity; }
|
||||
size_t capacity() const { return mTail.mCapacity; }
|
||||
|
||||
T* begin()
|
||||
{
|
||||
|
|
@ -753,10 +826,10 @@ private:
|
|||
/* This does the re-entrancy check plus several other sanity checks. */
|
||||
#define MOZ_REENTRANCY_GUARD_ET_AL \
|
||||
ReentrancyGuard g(*this); \
|
||||
MOZ_ASSERT_IF(usingInlineStorage(), mCapacity == kInlineCapacity); \
|
||||
MOZ_ASSERT(reserved() <= mCapacity); \
|
||||
MOZ_ASSERT_IF(usingInlineStorage(), mTail.mCapacity == kInlineCapacity); \
|
||||
MOZ_ASSERT(reserved() <= mTail.mCapacity); \
|
||||
MOZ_ASSERT(mLength <= reserved()); \
|
||||
MOZ_ASSERT(mLength <= mCapacity)
|
||||
MOZ_ASSERT(mLength <= mTail.mCapacity)
|
||||
|
||||
/* Vector Implementation */
|
||||
|
||||
|
|
@ -765,13 +838,12 @@ MOZ_ALWAYS_INLINE
|
|||
Vector<T, N, AP>::Vector(AP aAP)
|
||||
: AP(aAP)
|
||||
, mLength(0)
|
||||
, mCapacity(kInlineCapacity)
|
||||
, mTail(kInlineCapacity, 0)
|
||||
#ifdef DEBUG
|
||||
, mReserved(0)
|
||||
, mEntered(false)
|
||||
#endif
|
||||
{
|
||||
mBegin = static_cast<T*>(mStorage.addr());
|
||||
mBegin = inlineStorage();
|
||||
}
|
||||
|
||||
/* Move constructor. */
|
||||
|
|
@ -784,14 +856,14 @@ Vector<T, N, AllocPolicy>::Vector(Vector&& aRhs)
|
|||
#endif
|
||||
{
|
||||
mLength = aRhs.mLength;
|
||||
mCapacity = aRhs.mCapacity;
|
||||
mTail.mCapacity = aRhs.mTail.mCapacity;
|
||||
#ifdef DEBUG
|
||||
mReserved = aRhs.mReserved;
|
||||
mTail.mReserved = aRhs.mTail.mReserved;
|
||||
#endif
|
||||
|
||||
if (aRhs.usingInlineStorage()) {
|
||||
/* We can't move the buffer over in this case, so copy elements. */
|
||||
mBegin = static_cast<T*>(mStorage.addr());
|
||||
mBegin = inlineStorage();
|
||||
Impl::moveConstruct(mBegin, aRhs.beginNoCheck(), aRhs.endNoCheck());
|
||||
/*
|
||||
* Leave aRhs's mLength, mBegin, mCapacity, and mReserved as they are.
|
||||
|
|
@ -803,11 +875,11 @@ Vector<T, N, AllocPolicy>::Vector(Vector&& aRhs)
|
|||
* in-line storage.
|
||||
*/
|
||||
mBegin = aRhs.mBegin;
|
||||
aRhs.mBegin = static_cast<T*>(aRhs.mStorage.addr());
|
||||
aRhs.mCapacity = kInlineCapacity;
|
||||
aRhs.mBegin = aRhs.inlineStorage();
|
||||
aRhs.mTail.mCapacity = kInlineCapacity;
|
||||
aRhs.mLength = 0;
|
||||
#ifdef DEBUG
|
||||
aRhs.mReserved = 0;
|
||||
aRhs.mTail.mReserved = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -871,7 +943,7 @@ Vector<T, N, AP>::convertToHeapStorage(size_t aNewCap)
|
|||
/* Switch in heap buffer. */
|
||||
mBegin = newBuf;
|
||||
/* mLength is unchanged. */
|
||||
mCapacity = aNewCap;
|
||||
mTail.mCapacity = aNewCap;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -879,7 +951,7 @@ template<typename T, size_t N, class AP>
|
|||
MOZ_NEVER_INLINE bool
|
||||
Vector<T, N, AP>::growStorageBy(size_t aIncr)
|
||||
{
|
||||
MOZ_ASSERT(mLength + aIncr > mCapacity);
|
||||
MOZ_ASSERT(mLength + aIncr > mTail.mCapacity);
|
||||
|
||||
/*
|
||||
* When choosing a new capacity, its size should is as close to 2**N bytes
|
||||
|
|
@ -971,9 +1043,9 @@ Vector<T, N, AP>::initCapacity(size_t aRequest)
|
|||
return false;
|
||||
}
|
||||
mBegin = newbuf;
|
||||
mCapacity = aRequest;
|
||||
mTail.mCapacity = aRequest;
|
||||
#ifdef DEBUG
|
||||
mReserved = aRequest;
|
||||
mTail.mReserved = aRequest;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
|
@ -998,7 +1070,7 @@ Vector<T, N, AP>::maybeCheckSimulatedOOM(size_t aRequestedSize)
|
|||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (aRequestedSize <= mReserved) {
|
||||
if (aRequestedSize <= mTail.mReserved) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1011,7 +1083,7 @@ inline bool
|
|||
Vector<T, N, AP>::reserve(size_t aRequest)
|
||||
{
|
||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||
if (aRequest > mCapacity) {
|
||||
if (aRequest > mTail.mCapacity) {
|
||||
if (MOZ_UNLIKELY(!growStorageBy(aRequest - mLength))) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1019,11 +1091,11 @@ Vector<T, N, AP>::reserve(size_t aRequest)
|
|||
return false;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (aRequest > mReserved) {
|
||||
mReserved = aRequest;
|
||||
if (aRequest > mTail.mReserved) {
|
||||
mTail.mReserved = aRequest;
|
||||
}
|
||||
MOZ_ASSERT(mLength <= mReserved);
|
||||
MOZ_ASSERT(mReserved <= mCapacity);
|
||||
MOZ_ASSERT(mLength <= mTail.mReserved);
|
||||
MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1051,20 +1123,20 @@ MOZ_ALWAYS_INLINE bool
|
|||
Vector<T, N, AP>::growBy(size_t aIncr)
|
||||
{
|
||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||
if (aIncr > mCapacity - mLength) {
|
||||
if (aIncr > mTail.mCapacity - mLength) {
|
||||
if (MOZ_UNLIKELY(!growStorageBy(aIncr))) {
|
||||
return false;
|
||||
}
|
||||
} else if (!maybeCheckSimulatedOOM(mLength + aIncr)) {
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(mLength + aIncr <= mCapacity);
|
||||
MOZ_ASSERT(mLength + aIncr <= mTail.mCapacity);
|
||||
T* newend = endNoCheck() + aIncr;
|
||||
Impl::initialize(endNoCheck(), newend);
|
||||
mLength += aIncr;
|
||||
#ifdef DEBUG
|
||||
if (mLength > mReserved) {
|
||||
mReserved = mLength;
|
||||
if (mLength > mTail.mReserved) {
|
||||
mTail.mReserved = mLength;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
|
|
@ -1075,7 +1147,7 @@ MOZ_ALWAYS_INLINE bool
|
|||
Vector<T, N, AP>::growByUninitialized(size_t aIncr)
|
||||
{
|
||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||
if (aIncr > mCapacity - mLength) {
|
||||
if (aIncr > mTail.mCapacity - mLength) {
|
||||
if (MOZ_UNLIKELY(!growStorageBy(aIncr))) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1083,8 +1155,8 @@ Vector<T, N, AP>::growByUninitialized(size_t aIncr)
|
|||
return false;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (mLength + aIncr > mReserved) {
|
||||
mReserved = mLength + aIncr;
|
||||
if (mLength + aIncr > mTail.mReserved) {
|
||||
mTail.mReserved = mLength + aIncr;
|
||||
}
|
||||
#endif
|
||||
infallibleGrowByUninitialized(aIncr);
|
||||
|
|
@ -1142,10 +1214,10 @@ Vector<T, N, AP>::clearAndFree()
|
|||
return;
|
||||
}
|
||||
this->free_(beginNoCheck());
|
||||
mBegin = static_cast<T*>(mStorage.addr());
|
||||
mCapacity = kInlineCapacity;
|
||||
mBegin = inlineStorage();
|
||||
mTail.mCapacity = kInlineCapacity;
|
||||
#ifdef DEBUG
|
||||
mReserved = 0;
|
||||
mTail.mReserved = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -1162,7 +1234,7 @@ template<typename T, size_t N, class AP>
|
|||
inline bool
|
||||
Vector<T, N, AP>::canAppendWithoutRealloc(size_t aNeeded) const
|
||||
{
|
||||
return mLength + aNeeded <= mCapacity;
|
||||
return mLength + aNeeded <= mTail.mCapacity;
|
||||
}
|
||||
|
||||
template<typename T, size_t N, class AP>
|
||||
|
|
@ -1178,8 +1250,8 @@ template<typename U>
|
|||
MOZ_ALWAYS_INLINE void
|
||||
Vector<T, N, AP>::internalAppend(U&& aU)
|
||||
{
|
||||
MOZ_ASSERT(mLength + 1 <= mReserved);
|
||||
MOZ_ASSERT(mReserved <= mCapacity);
|
||||
MOZ_ASSERT(mLength + 1 <= mTail.mReserved);
|
||||
MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity);
|
||||
Impl::new_(endNoCheck(), Forward<U>(aU));
|
||||
++mLength;
|
||||
}
|
||||
|
|
@ -1189,7 +1261,7 @@ MOZ_ALWAYS_INLINE bool
|
|||
Vector<T, N, AP>::appendN(const T& aT, size_t aNeeded)
|
||||
{
|
||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||
if (mLength + aNeeded > mCapacity) {
|
||||
if (mLength + aNeeded > mTail.mCapacity) {
|
||||
if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1197,8 +1269,8 @@ Vector<T, N, AP>::appendN(const T& aT, size_t aNeeded)
|
|||
return false;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (mLength + aNeeded > mReserved) {
|
||||
mReserved = mLength + aNeeded;
|
||||
if (mLength + aNeeded > mTail.mReserved) {
|
||||
mTail.mReserved = mLength + aNeeded;
|
||||
}
|
||||
#endif
|
||||
internalAppendN(aT, aNeeded);
|
||||
|
|
@ -1209,8 +1281,8 @@ template<typename T, size_t N, class AP>
|
|||
MOZ_ALWAYS_INLINE void
|
||||
Vector<T, N, AP>::internalAppendN(const T& aT, size_t aNeeded)
|
||||
{
|
||||
MOZ_ASSERT(mLength + aNeeded <= mReserved);
|
||||
MOZ_ASSERT(mReserved <= mCapacity);
|
||||
MOZ_ASSERT(mLength + aNeeded <= mTail.mReserved);
|
||||
MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity);
|
||||
Impl::copyConstructN(endNoCheck(), aNeeded, aT);
|
||||
mLength += aNeeded;
|
||||
}
|
||||
|
|
@ -1275,7 +1347,7 @@ Vector<T, N, AP>::append(const U* aInsBegin, const U* aInsEnd)
|
|||
{
|
||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||
size_t aNeeded = PointerRangeSize(aInsBegin, aInsEnd);
|
||||
if (mLength + aNeeded > mCapacity) {
|
||||
if (mLength + aNeeded > mTail.mCapacity) {
|
||||
if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1283,8 +1355,8 @@ Vector<T, N, AP>::append(const U* aInsBegin, const U* aInsEnd)
|
|||
return false;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (mLength + aNeeded > mReserved) {
|
||||
mReserved = mLength + aNeeded;
|
||||
if (mLength + aNeeded > mTail.mReserved) {
|
||||
mTail.mReserved = mLength + aNeeded;
|
||||
}
|
||||
#endif
|
||||
internalAppend(aInsBegin, aNeeded);
|
||||
|
|
@ -1296,8 +1368,8 @@ template<typename U>
|
|||
MOZ_ALWAYS_INLINE void
|
||||
Vector<T, N, AP>::internalAppend(const U* aInsBegin, size_t aInsLength)
|
||||
{
|
||||
MOZ_ASSERT(mLength + aInsLength <= mReserved);
|
||||
MOZ_ASSERT(mReserved <= mCapacity);
|
||||
MOZ_ASSERT(mLength + aInsLength <= mTail.mReserved);
|
||||
MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity);
|
||||
Impl::copyConstruct(endNoCheck(), aInsBegin, aInsBegin + aInsLength);
|
||||
mLength += aInsLength;
|
||||
}
|
||||
|
|
@ -1308,7 +1380,7 @@ MOZ_ALWAYS_INLINE bool
|
|||
Vector<T, N, AP>::append(U&& aU)
|
||||
{
|
||||
MOZ_REENTRANCY_GUARD_ET_AL;
|
||||
if (mLength == mCapacity) {
|
||||
if (mLength == mTail.mCapacity) {
|
||||
if (MOZ_UNLIKELY(!growStorageBy(1))) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1316,8 +1388,8 @@ Vector<T, N, AP>::append(U&& aU)
|
|||
return false;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (mLength + 1 > mReserved) {
|
||||
mReserved = mLength + 1;
|
||||
if (mLength + 1 > mTail.mReserved) {
|
||||
mTail.mReserved = mLength + 1;
|
||||
}
|
||||
#endif
|
||||
internalAppend(Forward<U>(aU));
|
||||
|
|
@ -1370,11 +1442,11 @@ Vector<T, N, AP>::extractRawBuffer()
|
|||
}
|
||||
|
||||
T* ret = mBegin;
|
||||
mBegin = static_cast<T*>(mStorage.addr());
|
||||
mBegin = inlineStorage();
|
||||
mLength = 0;
|
||||
mCapacity = kInlineCapacity;
|
||||
mTail.mCapacity = kInlineCapacity;
|
||||
#ifdef DEBUG
|
||||
mReserved = 0;
|
||||
mTail.mReserved = 0;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1396,11 +1468,11 @@ Vector<T, N, AP>::extractOrCopyRawBuffer()
|
|||
|
||||
Impl::moveConstruct(copy, beginNoCheck(), endNoCheck());
|
||||
Impl::destroy(beginNoCheck(), endNoCheck());
|
||||
mBegin = static_cast<T*>(mStorage.addr());
|
||||
mBegin = inlineStorage();
|
||||
mLength = 0;
|
||||
mCapacity = kInlineCapacity;
|
||||
mTail.mCapacity = kInlineCapacity;
|
||||
#ifdef DEBUG
|
||||
mReserved = 0;
|
||||
mTail.mReserved = 0;
|
||||
#endif
|
||||
return copy;
|
||||
}
|
||||
|
|
@ -1424,19 +1496,19 @@ Vector<T, N, AP>::replaceRawBuffer(T* aP, size_t aLength)
|
|||
* otherwise be acceptable. Maybe this behaviour should be
|
||||
* specifiable with an argument to this function.
|
||||
*/
|
||||
mBegin = static_cast<T*>(mStorage.addr());
|
||||
mBegin = inlineStorage();
|
||||
mLength = aLength;
|
||||
mCapacity = kInlineCapacity;
|
||||
mTail.mCapacity = kInlineCapacity;
|
||||
Impl::moveConstruct(mBegin, aP, aP + aLength);
|
||||
Impl::destroy(aP, aP + aLength);
|
||||
this->free_(aP);
|
||||
} else {
|
||||
mBegin = aP;
|
||||
mLength = aLength;
|
||||
mCapacity = aLength;
|
||||
mTail.mCapacity = aLength;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
mReserved = aLength;
|
||||
mTail.mReserved = aLength;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -1475,9 +1547,9 @@ Vector<T, N, AP>::swap(Vector& aOther)
|
|||
}
|
||||
|
||||
Swap(mLength, aOther.mLength);
|
||||
Swap(mCapacity, aOther.mCapacity);
|
||||
Swap(mTail.mCapacity, aOther.mTail.mCapacity);
|
||||
#ifdef DEBUG
|
||||
Swap(mReserved, aOther.mReserved);
|
||||
Swap(mTail.mReserved, aOther.mTail.mReserved);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -396,6 +396,49 @@ mozilla::detail::VectorTesting::testInsert()
|
|||
MOZ_RELEASE_ASSERT(S::destructCount == 1);
|
||||
}
|
||||
|
||||
// Declare but leave (permanently) incomplete.
|
||||
struct Incomplete;
|
||||
|
||||
// We could even *construct* a Vector<Incomplete, 0> if we wanted. But we can't
|
||||
// destruct it, so it's not worth the trouble.
|
||||
static_assert(sizeof(Vector<Incomplete, 0>) > 0,
|
||||
"Vector of an incomplete type will compile");
|
||||
|
||||
// Vector with no inline storage should occupy the absolute minimum space in
|
||||
// non-debug builds. (Debug adds a laundry list of other constraints, none
|
||||
// directly relevant to shipping builds, that aren't worth precisely modeling.)
|
||||
#ifndef DEBUG
|
||||
|
||||
template<typename T>
|
||||
struct NoInlineStorageLayout
|
||||
{
|
||||
T* mBegin;
|
||||
size_t mLength;
|
||||
struct CRAndStorage {
|
||||
size_t mCapacity;
|
||||
} mTail;
|
||||
};
|
||||
|
||||
// Only one of these should be necessary, but test a few of them for good
|
||||
// measure.
|
||||
static_assert(sizeof(Vector<int, 0>) == sizeof(NoInlineStorageLayout<int>),
|
||||
"Vector of int without inline storage shouldn't occupy dead "
|
||||
"space for that absence of storage");
|
||||
|
||||
static_assert(sizeof(Vector<bool, 0>) == sizeof(NoInlineStorageLayout<bool>),
|
||||
"Vector of bool without inline storage shouldn't occupy dead "
|
||||
"space for that absence of storage");
|
||||
|
||||
static_assert(sizeof(Vector<S, 0>) == sizeof(NoInlineStorageLayout<S>),
|
||||
"Vector of S without inline storage shouldn't occupy dead "
|
||||
"space for that absence of storage");
|
||||
|
||||
static_assert(sizeof(Vector<Incomplete, 0>) == sizeof(NoInlineStorageLayout<Incomplete>),
|
||||
"Vector of an incomplete class without inline storage shouldn't "
|
||||
"occupy dead space for that absence of storage");
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4994,6 +4994,16 @@ fi
|
|||
AC_DEFINE_UNQUOTED(MOZ_MACBUNDLE_ID,$MOZ_MACBUNDLE_ID)
|
||||
AC_SUBST(MOZ_MACBUNDLE_ID)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Mac bundle codesign identity
|
||||
dnl ========================================================
|
||||
MOZ_ARG_WITH_STRING(macbundle-identity,
|
||||
[ --with-macbundle-identity=identity
|
||||
Identity to codesign the Mac application bundle],
|
||||
[ MOZ_MACBUNDLE_IDENTITY="$withval"])
|
||||
|
||||
AC_SUBST(MOZ_MACBUNDLE_IDENTITY)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Child Process Name for IPC
|
||||
dnl ========================================================
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ def create_dmg(source_directory, output_dmg, volume_name, extra_files):
|
|||
if is_linux:
|
||||
check_tools('DMG_TOOL', 'GENISOIMAGE')
|
||||
with mozfile.TemporaryDirectory() as tmpdir:
|
||||
import buildconfig
|
||||
stagedir = os.path.join(tmpdir, 'stage')
|
||||
os.mkdir(stagedir)
|
||||
# Copy the app bundle over using rsync
|
||||
|
|
@ -118,4 +119,9 @@ def create_dmg(source_directory, output_dmg, volume_name, extra_files):
|
|||
# Set the folder attributes to use a custom icon
|
||||
set_folder_icon(stagedir)
|
||||
chmod(stagedir)
|
||||
if not is_linux:
|
||||
identity = buildconfig.substs['MOZ_MACBUNDLE_IDENTITY']
|
||||
if identity != '':
|
||||
appbundle = os.path.join(stagedir, buildconfig.substs['MOZ_MACBUNDLE_NAME'])
|
||||
subprocess.check_call(['codesign', '--deep', '-s', identity, appbundle])
|
||||
create_dmg_from_staged(stagedir, output_dmg, tmpdir, volume_name)
|
||||
|
|
|
|||
|
|
@ -172,10 +172,17 @@ CTLogVerifier::Verify(const LogEntry& entry,
|
|||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// sct.extensions may be empty. If it is, sctExtensionsInput will remain in
|
||||
// its default state, which is valid but of length 0.
|
||||
Input sctExtensionsInput;
|
||||
rv = BufferToInput(sct.extensions, sctExtensionsInput);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
if (sct.extensions.length() > 0) {
|
||||
rv = sctExtensionsInput.Init(sct.extensions.begin(),
|
||||
sct.extensions.length());
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
Buffer serializedData;
|
||||
|
|
|
|||
|
|
@ -115,6 +115,9 @@ struct SignedCertificateTimestamp
|
|||
|
||||
inline pkix::Result BufferToInput(const Buffer& buffer, pkix::Input& input)
|
||||
{
|
||||
if (buffer.length() == 0) {
|
||||
return pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
}
|
||||
return input.Init(buffer.begin(), buffer.length());
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue