Backed out changeset 74a0a0207e08 (bug 1338217) for linux failures

This commit is contained in:
Carsten "Tomcat" Book 2017-05-03 15:27:26 +02:00
Родитель b3a8a13d69
Коммит 0b5ec8c1f2
13 изменённых файлов: 217 добавлений и 502 удалений

Просмотреть файл

@ -272,7 +272,6 @@ struct StatsClosure
SourceSet seenSources; SourceSet seenSources;
wasm::Metadata::SeenSet wasmSeenMetadata; wasm::Metadata::SeenSet wasmSeenMetadata;
wasm::ShareableBytes::SeenSet wasmSeenBytes; wasm::ShareableBytes::SeenSet wasmSeenBytes;
wasm::Code::SeenSet wasmSeenCode;
wasm::Table::SeenSet wasmSeenTables; wasm::Table::SeenSet wasmSeenTables;
bool anonymize; bool anonymize;
@ -286,7 +285,6 @@ struct StatsClosure
return seenSources.init() && return seenSources.init() &&
wasmSeenMetadata.init() && wasmSeenMetadata.init() &&
wasmSeenBytes.init() && wasmSeenBytes.init() &&
wasmSeenCode.init() &&
wasmSeenTables.init(); wasmSeenTables.init();
} }
}; };
@ -477,7 +475,6 @@ StatsCellCallback(JSRuntime* rt, void* data, void* thing, JS::TraceKind traceKin
module.addSizeOfMisc(rtStats->mallocSizeOf_, module.addSizeOfMisc(rtStats->mallocSizeOf_,
&closure->wasmSeenMetadata, &closure->wasmSeenMetadata,
&closure->wasmSeenBytes, &closure->wasmSeenBytes,
&closure->wasmSeenCode,
&info.objectsNonHeapCodeWasm, &info.objectsNonHeapCodeWasm,
&info.objectsMallocHeapMisc); &info.objectsMallocHeapMisc);
} else if (obj->is<WasmInstanceObject>()) { } else if (obj->is<WasmInstanceObject>()) {
@ -487,7 +484,6 @@ StatsCellCallback(JSRuntime* rt, void* data, void* thing, JS::TraceKind traceKin
instance.addSizeOfMisc(rtStats->mallocSizeOf_, instance.addSizeOfMisc(rtStats->mallocSizeOf_,
&closure->wasmSeenMetadata, &closure->wasmSeenMetadata,
&closure->wasmSeenBytes, &closure->wasmSeenBytes,
&closure->wasmSeenCode,
&closure->wasmSeenTables, &closure->wasmSeenTables,
&info.objectsNonHeapCodeWasm, &info.objectsNonHeapCodeWasm,
&info.objectsMallocHeapMisc); &info.objectsMallocHeapMisc);

Просмотреть файл

@ -34,6 +34,7 @@
_(GeckoProfilerStrings, 500) \ _(GeckoProfilerStrings, 500) \
_(ProtectedRegionTree, 500) \ _(ProtectedRegionTree, 500) \
_(WasmSigIdSet, 500) \ _(WasmSigIdSet, 500) \
_(WasmCodeProfilingLabels, 500) \
_(ShellOffThreadState, 500) \ _(ShellOffThreadState, 500) \
_(SimulatorCacheLock, 500) \ _(SimulatorCacheLock, 500) \
_(Arm64SimulatorLock, 500) \ _(Arm64SimulatorLock, 500) \
@ -45,9 +46,6 @@
_(IcuTimeZoneStateMutex, 500) \ _(IcuTimeZoneStateMutex, 500) \
_(ProcessExecutableRegion, 500) \ _(ProcessExecutableRegion, 500) \
\ \
/* WasmCodeProfilingLabels > PromiseTaskPtrVector */ \
_(WasmCodeProfilingLabels, 550) \
\
_(TraceLoggerGraphState, 600) \ _(TraceLoggerGraphState, 600) \
_(VTuneLock, 600) _(VTuneLock, 600)

Просмотреть файл

@ -64,7 +64,7 @@ RoundupCodeLength(uint32_t codeLength)
} }
static uint8_t* static uint8_t*
AllocateCodeBytes(uint32_t codeLength) AllocateCodeSegment(JSContext* cx, uint32_t codeLength)
{ {
codeLength = RoundupCodeLength(codeLength); codeLength = RoundupCodeLength(codeLength);
@ -83,22 +83,20 @@ AllocateCodeBytes(uint32_t codeLength)
} }
} }
if (!p) if (!p) {
ReportOutOfMemory(cx);
return nullptr; return nullptr;
}
// We account for the bytes allocated in WasmModuleObject::create, where we cx->zone()->updateJitCodeMallocBytes(codeLength);
// have the necessary JSContext.
wasmCodeAllocations++; wasmCodeAllocations++;
return (uint8_t*)p; return (uint8_t*)p;
} }
static void static void
FreeCodeBytes(uint8_t* bytes, uint32_t codeLength) FreeCodeSegment(uint8_t* bytes, uint32_t codeLength)
{ {
MOZ_ASSERT(wasmCodeAllocations > 0);
wasmCodeAllocations--;
codeLength = RoundupCodeLength(codeLength); codeLength = RoundupCodeLength(codeLength);
#ifdef MOZ_VTUNE #ifdef MOZ_VTUNE
vtune::UnmarkBytes(bytes, codeLength); vtune::UnmarkBytes(bytes, codeLength);
@ -138,33 +136,6 @@ StaticallyLink(const CodeSegment& cs, const LinkData& linkData)
return true; return true;
} }
static void
StaticallyUnlink(uint8_t* base, const LinkData& linkData)
{
for (LinkData::InternalLink link : linkData.internalLinks) {
uint8_t* patchAt = base + link.patchAtOffset;
void* target = 0;
if (link.isRawPointerPatch())
*(void**)(patchAt) = target;
else
Assembler::PatchInstructionImmediate(patchAt, PatchedImmPtr(target));
}
for (auto imm : MakeEnumeratedRange(SymbolicAddress::Limit)) {
const Uint32Vector& offsets = linkData.symbolicLinks[imm];
if (offsets.empty())
continue;
void* target = SymbolicAddressTarget(imm);
for (uint32_t offset : offsets) {
uint8_t* patchAt = base + offset;
Assembler::PatchDataWithValueCheck(CodeLocationLabel(patchAt),
PatchedImmPtr((void*)-1),
PatchedImmPtr(target));
}
}
}
static void static void
SendCodeRangesToProfiler(const CodeSegment& cs, const Bytes& bytecode, const Metadata& metadata) SendCodeRangesToProfiler(const CodeSegment& cs, const Bytes& bytecode, const Metadata& metadata)
{ {
@ -214,99 +185,53 @@ SendCodeRangesToProfiler(const CodeSegment& cs, const Bytes& bytecode, const Met
} }
/* static */ UniqueConstCodeSegment /* static */ UniqueConstCodeSegment
CodeSegment::create(jit::MacroAssembler& masm, CodeSegment::create(JSContext* cx,
const ShareableBytes& bytecode, const Bytes& codeBytes,
const SharedBytes& bytecode,
const LinkData& linkData, const LinkData& linkData,
const Metadata& metadata) const Metadata& metadata)
{ {
// Round up the code size to page size since this is eventually required by MOZ_ASSERT(codeBytes.length() % gc::SystemPageSize() == 0);
// the executable-code allocator and for setting memory protection. MOZ_ASSERT(linkData.functionCodeLength < codeBytes.length());
uint32_t bytesNeeded = masm.bytesNeeded();
uint32_t padding = ComputeByteAlignment(bytesNeeded, gc::SystemPageSize());
uint32_t codeLength = bytesNeeded + padding;
MOZ_ASSERT(linkData.functionCodeLength < codeLength);
uint8_t* codeBase = AllocateCodeBytes(codeLength);
if (!codeBase)
return nullptr;
// We'll flush the icache after static linking, in initialize().
masm.executableCopy(codeBase, /* flushICache = */ false);
// Zero the padding.
memset(codeBase + bytesNeeded, 0, padding);
return create(codeBase, codeLength, bytecode, linkData, metadata);
}
/* static */ UniqueConstCodeSegment
CodeSegment::create(const Bytes& unlinkedBytes, const ShareableBytes& bytecode,
const LinkData& linkData, const Metadata& metadata)
{
uint32_t codeLength = unlinkedBytes.length();
MOZ_ASSERT(codeLength % gc::SystemPageSize() == 0);
uint8_t* codeBytes = AllocateCodeBytes(codeLength);
if (!codeBytes)
return nullptr;
memcpy(codeBytes, unlinkedBytes.begin(), codeLength);
return create(codeBytes, codeLength, bytecode, linkData, metadata);
}
/* static */ UniqueConstCodeSegment
CodeSegment::create(uint8_t* codeBase, uint32_t codeLength,
const ShareableBytes& bytecode,
const LinkData& linkData,
const Metadata& metadata)
{
// These should always exist and should never be first in the code segment. // These should always exist and should never be first in the code segment.
MOZ_ASSERT(linkData.interruptOffset != 0); MOZ_ASSERT(linkData.interruptOffset != 0);
MOZ_ASSERT(linkData.outOfBoundsOffset != 0); MOZ_ASSERT(linkData.outOfBoundsOffset != 0);
MOZ_ASSERT(linkData.unalignedAccessOffset != 0); MOZ_ASSERT(linkData.unalignedAccessOffset != 0);
auto cs = js::MakeUnique<CodeSegment>(); uint8_t* codeBase = AllocateCodeSegment(cx, codeBytes.length());
if (!codeBase)
return nullptr;
auto cs = cx->make_unique<const CodeSegment>(codeBase, linkData.functionCodeLength,
codeBytes.length(),
codeBase + linkData.interruptOffset,
codeBase + linkData.outOfBoundsOffset,
codeBase + linkData.unalignedAccessOffset);
if (!cs) { if (!cs) {
FreeCodeBytes(codeBase, codeLength); FreeCodeSegment(codeBase, codeBytes.length());
return nullptr; return nullptr;
} }
if (!cs->initialize(codeBase, codeLength, bytecode, linkData, metadata))
return nullptr;
return UniqueConstCodeSegment(cs.release());
}
bool
CodeSegment::initialize(uint8_t* codeBase, uint32_t codeLength,
const ShareableBytes& bytecode,
const LinkData& linkData,
const Metadata& metadata)
{ {
MOZ_ASSERT(bytes_ == nullptr); JitContext jcx(CompileRuntime::get(cx->compartment()->runtimeFromAnyThread()));
AutoFlushICache afc("CodeSegment::create");
AutoFlushICache::setRange(uintptr_t(codeBase), cs->length());
bytes_ = codeBase; memcpy(codeBase, codeBytes.begin(), codeBytes.length());
// This CodeSegment instance now owns the code bytes, and the CodeSegment's if (!StaticallyLink(*cs, linkData))
// destructor will take care of freeing those bytes in the case of error. return nullptr;
functionLength_ = linkData.functionCodeLength; }
length_ = codeLength;
interruptCode_ = codeBase + linkData.interruptOffset;
outOfBoundsCode_ = codeBase + linkData.outOfBoundsOffset;
unalignedAccessCode_ = codeBase + linkData.unalignedAccessOffset;
if (!StaticallyLink(*this, linkData))
return false;
ExecutableAllocator::cacheFlush(codeBase, RoundupCodeLength(codeLength));
// Reprotect the whole region to avoid having separate RW and RX mappings. // Reprotect the whole region to avoid having separate RW and RX mappings.
if (!ExecutableAllocator::makeExecutable(codeBase, RoundupCodeLength(codeLength))) if (!ExecutableAllocator::makeExecutable(codeBase, RoundupCodeLength(cs->length()))) {
return false; ReportOutOfMemory(cx);
return nullptr;
}
SendCodeRangesToProfiler(*this, bytecode.bytes, metadata); SendCodeRangesToProfiler(*cs, bytecode->bytes, metadata);
return true; return cs;
} }
CodeSegment::~CodeSegment() CodeSegment::~CodeSegment()
@ -314,69 +239,12 @@ CodeSegment::~CodeSegment()
if (!bytes_) if (!bytes_)
return; return;
MOZ_ASSERT(wasmCodeAllocations > 0);
wasmCodeAllocations--;
MOZ_ASSERT(length() > 0); MOZ_ASSERT(length() > 0);
FreeCodeBytes(bytes_, length());
}
UniqueConstBytes FreeCodeSegment(bytes_, length());
CodeSegment::unlinkedBytesForDebugging(const LinkData& linkData) const
{
UniqueBytes unlinkedBytes = js::MakeUnique<Bytes>();
if (!unlinkedBytes)
return nullptr;
if (!unlinkedBytes->append(base(), length()))
return nullptr;
StaticallyUnlink(unlinkedBytes->begin(), linkData);
return UniqueConstBytes(unlinkedBytes.release());
}
size_t
CodeSegment::serializedSize() const
{
return sizeof(uint32_t) + length_;
}
void
CodeSegment::addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t* code, size_t* data) const
{
*data += mallocSizeOf(this);
*code += RoundupCodeLength(length_);
}
uint8_t*
CodeSegment::serialize(uint8_t* cursor, const LinkData& linkData) const
{
cursor = WriteScalar<uint32_t>(cursor, length_);
uint8_t* base = cursor;
cursor = WriteBytes(cursor, bytes_, length_);
StaticallyUnlink(base, linkData);
return cursor;
}
const uint8_t*
CodeSegment::deserialize(const uint8_t* cursor, const ShareableBytes& bytecode,
const LinkData& linkData, const Metadata& metadata)
{
uint32_t length;
cursor = ReadScalar<uint32_t>(cursor, &length);
if (!cursor)
return nullptr;
MOZ_ASSERT(length_ % gc::SystemPageSize() == 0);
uint8_t* bytes = AllocateCodeBytes(length);
if (!bytes)
return nullptr;
cursor = ReadBytes(cursor, bytes, length);
if (!cursor) {
FreeCodeBytes(bytes, length);
return nullptr;
}
if (!initialize(bytes, length, bytecode, linkData, metadata))
return nullptr;
return cursor;
} }
size_t size_t
@ -623,11 +491,6 @@ Code::Code(UniqueConstCodeSegment segment,
MOZ_ASSERT_IF(metadata_->debugEnabled, maybeBytecode); MOZ_ASSERT_IF(metadata_->debugEnabled, maybeBytecode);
} }
Code::Code()
: profilingLabels_(mutexid::WasmCodeProfilingLabels, CacheableCharsVector())
{
}
struct CallSiteRetAddrOffset struct CallSiteRetAddrOffset
{ {
const CallSiteVector& callSites; const CallSiteVector& callSites;
@ -637,73 +500,25 @@ struct CallSiteRetAddrOffset
} }
}; };
size_t
Code::serializedSize() const
{
return metadata().serializedSize() +
segment().serializedSize();
}
uint8_t*
Code::serialize(uint8_t* cursor, const LinkData& linkData) const
{
MOZ_RELEASE_ASSERT(!metadata().debugEnabled);
cursor = metadata().serialize(cursor);
cursor = segment().serialize(cursor, linkData);
return cursor;
}
const uint8_t*
Code::deserialize(const uint8_t* cursor, const SharedBytes& bytecode, const LinkData& linkData,
Metadata* maybeMetadata)
{
MutableMetadata metadata;
if (maybeMetadata) {
metadata = maybeMetadata;
} else {
metadata = js_new<Metadata>();
if (!metadata)
return nullptr;
}
cursor = metadata->deserialize(cursor);
if (!cursor)
return nullptr;
UniqueCodeSegment codeSegment = js::MakeUnique<CodeSegment>();
if (!codeSegment)
return nullptr;
cursor = codeSegment->deserialize(cursor, *bytecode, linkData, *metadata);
if (!cursor)
return nullptr;
segment_ = UniqueConstCodeSegment(codeSegment.release());
metadata_ = metadata;
maybeBytecode_ = bytecode;
return cursor;
}
const CallSite* const CallSite*
Code::lookupCallSite(void* returnAddress) const Code::lookupCallSite(void* returnAddress) const
{ {
uint32_t target = ((uint8_t*)returnAddress) - segment_->base(); uint32_t target = ((uint8_t*)returnAddress) - segment_->base();
size_t lowerBound = 0; size_t lowerBound = 0;
size_t upperBound = metadata().callSites.length(); size_t upperBound = metadata_->callSites.length();
size_t match; size_t match;
if (!BinarySearch(CallSiteRetAddrOffset(metadata().callSites), lowerBound, upperBound, target, &match)) if (!BinarySearch(CallSiteRetAddrOffset(metadata_->callSites), lowerBound, upperBound, target, &match))
return nullptr; return nullptr;
return &metadata().callSites[match]; return &metadata_->callSites[match];
} }
const CodeRange* const CodeRange*
Code::lookupRange(void* pc) const Code::lookupRange(void* pc) const
{ {
CodeRange::OffsetInCode target((uint8_t*)pc - segment_->base()); CodeRange::OffsetInCode target((uint8_t*)pc - segment_->base());
return LookupInSorted(metadata().codeRanges, target); return LookupInSorted(metadata_->codeRanges, target);
} }
struct MemoryAccessOffset struct MemoryAccessOffset
@ -722,20 +537,20 @@ Code::lookupMemoryAccess(void* pc) const
uint32_t target = ((uint8_t*)pc) - segment_->base(); uint32_t target = ((uint8_t*)pc) - segment_->base();
size_t lowerBound = 0; size_t lowerBound = 0;
size_t upperBound = metadata().memoryAccesses.length(); size_t upperBound = metadata_->memoryAccesses.length();
size_t match; size_t match;
if (!BinarySearch(MemoryAccessOffset(metadata().memoryAccesses), lowerBound, upperBound, target, &match)) if (!BinarySearch(MemoryAccessOffset(metadata_->memoryAccesses), lowerBound, upperBound, target, &match))
return nullptr; return nullptr;
return &metadata().memoryAccesses[match]; return &metadata_->memoryAccesses[match];
} }
bool bool
Code::getFuncName(uint32_t funcIndex, UTF8Bytes* name) const Code::getFuncName(uint32_t funcIndex, UTF8Bytes* name) const
{ {
const Bytes* maybeBytecode = maybeBytecode_ ? &maybeBytecode_.get()->bytes : nullptr; const Bytes* maybeBytecode = maybeBytecode_ ? &maybeBytecode_.get()->bytes : nullptr;
return metadata().getFuncName(maybeBytecode, funcIndex, name); return metadata_->getFuncName(maybeBytecode, funcIndex, name);
} }
JSAtom* JSAtom*
@ -765,7 +580,7 @@ Code::ensureProfilingLabels(bool profilingEnabled) const
if (!labels->empty()) if (!labels->empty())
return; return;
for (const CodeRange& codeRange : metadata().codeRanges) { for (const CodeRange& codeRange : metadata_->codeRanges) {
if (!codeRange.isFunction()) if (!codeRange.isFunction())
continue; continue;
@ -777,7 +592,7 @@ Code::ensureProfilingLabels(bool profilingEnabled) const
if (!getFuncName(codeRange.funcIndex(), &name) || !name.append(" (", 2)) if (!getFuncName(codeRange.funcIndex(), &name) || !name.append(" (", 2))
return; return;
if (const char* filename = metadata().filename.get()) { if (const char* filename = metadata_->filename.get()) {
if (!name.append(filename, strlen(filename))) if (!name.append(filename, strlen(filename)))
return; return;
} else { } else {
@ -816,24 +631,15 @@ Code::profilingLabel(uint32_t funcIndex) const
} }
void void
Code::addSizeOfMiscIfNotSeen(MallocSizeOf mallocSizeOf, Code::addSizeOfMisc(MallocSizeOf mallocSizeOf,
Metadata::SeenSet* seenMetadata, Metadata::SeenSet* seenMetadata,
ShareableBytes::SeenSet* seenBytes, ShareableBytes::SeenSet* seenBytes,
Code::SeenSet* seenCode,
size_t* code, size_t* code,
size_t* data) const size_t* data) const
{ {
auto p = seenCode->lookupForAdd(this); *code += segment_->length();
if (p)
return;
bool ok = seenCode->add(p, this);
(void)ok; // oh well
*data += mallocSizeOf(this) + *data += mallocSizeOf(this) +
metadata().sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenMetadata) + metadata_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenMetadata);
profilingLabels_.lock()->sizeOfExcludingThis(mallocSizeOf);
segment_->addSizeOfMisc(mallocSizeOf, code, data);
if (maybeBytecode_) if (maybeBytecode_)
*data += maybeBytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes); *data += maybeBytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);

Просмотреть файл

@ -53,7 +53,6 @@ typedef RefPtr<const ShareableBytes> SharedBytes;
// A wasm CodeSegment owns the allocated executable code for a wasm module. // A wasm CodeSegment owns the allocated executable code for a wasm module.
class CodeSegment; class CodeSegment;
typedef UniquePtr<CodeSegment> UniqueCodeSegment;
typedef UniquePtr<const CodeSegment> UniqueConstCodeSegment; typedef UniquePtr<const CodeSegment> UniqueConstCodeSegment;
class CodeSegment class CodeSegment
@ -71,40 +70,32 @@ class CodeSegment
uint8_t* outOfBoundsCode_; uint8_t* outOfBoundsCode_;
uint8_t* unalignedAccessCode_; uint8_t* unalignedAccessCode_;
// This assumes ownership of the codeBytes, and deletes them in the event of error. CodeSegment(uint8_t* bytes, uint32_t functionLength, uint32_t length, uint8_t* interruptCode,
bool initialize(uint8_t* codeBase, uint32_t codeLength, const ShareableBytes& bytecode, uint8_t* outOfBoundsCode, uint8_t* unalignedAccessCode)
const LinkData& linkData, const Metadata& metadata); : bytes_(bytes),
functionLength_(functionLength),
length_(length),
interruptCode_(interruptCode),
outOfBoundsCode_(outOfBoundsCode),
unalignedAccessCode_(unalignedAccessCode)
{
}
protected:
CodeSegment() { PodZero(this); }
template <class> friend struct js::MallocProvider;
// codeBytes must be executable memory.
// This assumes ownership of the codeBytes, and deletes them in the event of error.
static UniqueConstCodeSegment create(uint8_t* codeBytes,
uint32_t codeLength,
const ShareableBytes& bytecode,
const LinkData& linkData,
const Metadata& metadata);
public:
CodeSegment(const CodeSegment&) = delete; CodeSegment(const CodeSegment&) = delete;
CodeSegment(CodeSegment&&) = delete;
void operator=(const CodeSegment&) = delete; void operator=(const CodeSegment&) = delete;
void operator=(CodeSegment&&) = delete;
CodeSegment() public:
: bytes_(nullptr), static UniqueConstCodeSegment create(JSContext* cx,
functionLength_(0), const Bytes& codeBytes,
length_(0), const SharedBytes& bytecode,
interruptCode_(nullptr),
outOfBoundsCode_(nullptr),
unalignedAccessCode_(nullptr)
{}
static UniqueConstCodeSegment create(jit::MacroAssembler& masm,
const ShareableBytes& bytecode,
const LinkData& linkData, const LinkData& linkData,
const Metadata& metadata); const Metadata& metadata);
static UniqueConstCodeSegment create(const Bytes& codeBytes,
const ShareableBytes& bytecode,
const LinkData& linkData,
const Metadata& metadata);
~CodeSegment(); ~CodeSegment();
uint8_t* base() const { return bytes_; } uint8_t* base() const { return bytes_; }
@ -126,15 +117,6 @@ class CodeSegment
bool containsCodePC(const void* pc) const { bool containsCodePC(const void* pc) const {
return pc >= base() && pc < (base() + length_); return pc >= base() && pc < (base() + length_);
} }
UniqueConstBytes unlinkedBytesForDebugging(const LinkData& linkData) const;
size_t serializedSize() const;
uint8_t* serialize(uint8_t* cursor, const LinkData& linkData) const;
const uint8_t* deserialize(const uint8_t* cursor, const ShareableBytes& bytecode,
const LinkData& linkData, const Metadata& metadata);
void addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t* code, size_t* data) const;
}; };
// A FuncExport represents a single function definition inside a wasm Module // A FuncExport represents a single function definition inside a wasm Module
@ -390,14 +372,12 @@ typedef RefPtr<const Metadata> SharedMetadata;
class Code : public ShareableBase<Code> class Code : public ShareableBase<Code>
{ {
UniqueConstCodeSegment segment_; const UniqueConstCodeSegment segment_;
SharedMetadata metadata_; const SharedMetadata metadata_;
SharedBytes maybeBytecode_; const SharedBytes maybeBytecode_;
ExclusiveData<CacheableCharsVector> profilingLabels_; const ExclusiveData<CacheableCharsVector> profilingLabels_;
public: public:
Code();
Code(UniqueConstCodeSegment segment, Code(UniqueConstCodeSegment segment,
const Metadata& metadata, const Metadata& metadata,
const ShareableBytes* maybeBytecode); const ShareableBytes* maybeBytecode);
@ -425,25 +405,16 @@ class Code : public ShareableBase<Code>
// about:memory reporting: // about:memory reporting:
void addSizeOfMiscIfNotSeen(MallocSizeOf mallocSizeOf, void addSizeOfMisc(MallocSizeOf mallocSizeOf,
Metadata::SeenSet* seenMetadata, Metadata::SeenSet* seenMetadata,
ShareableBytes::SeenSet* seenBytes, ShareableBytes::SeenSet* seenBytes,
Code::SeenSet* seenCode,
size_t* code, size_t* code,
size_t* data) const; size_t* data) const;
// A Code object is serialized as the length and bytes of the machine code WASM_DECLARE_SERIALIZABLE(Code);
// after statically unlinking it; the Code is then later recreated from the
// machine code and other parts.
size_t serializedSize() const;
uint8_t* serialize(uint8_t* cursor, const LinkData& linkData) const;
const uint8_t* deserialize(const uint8_t* cursor, const SharedBytes& bytecode,
const LinkData& linkData, Metadata* maybeMetadata);
}; };
typedef RefPtr<const Code> SharedCode; typedef RefPtr<const Code> SharedCode;
typedef RefPtr<Code> MutableCode;
} // namespace wasm } // namespace wasm
} // namespace js } // namespace js

Просмотреть файл

@ -75,22 +75,15 @@ GeneratedSourceMap::searchLineByOffset(JSContext* cx, uint32_t offset, size_t* e
return true; return true;
} }
size_t
GeneratedSourceMap::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
{
size_t size = exprlocs_.sizeOfExcludingThis(mallocSizeOf);
if (sortedByOffsetExprLocIndices_)
size += sortedByOffsetExprLocIndices_->sizeOfIncludingThis(mallocSizeOf);
return size;
}
DebugState::DebugState(SharedCode code, DebugState::DebugState(SharedCode code,
const Metadata& metadata,
const ShareableBytes* maybeBytecode) const ShareableBytes* maybeBytecode)
: code_(Move(code)), : code_(Move(code)),
metadata_(&metadata),
maybeBytecode_(maybeBytecode), maybeBytecode_(maybeBytecode),
enterAndLeaveFrameTrapsCounter_(0) enterAndLeaveFrameTrapsCounter_(0)
{ {
MOZ_ASSERT_IF(debugEnabled(), maybeBytecode); MOZ_ASSERT_IF(metadata_->debugEnabled, maybeBytecode);
} }
const char enabledMessage[] = const char enabledMessage[] =
@ -164,7 +157,7 @@ struct LineComparator
bool bool
DebugState::getLineOffsets(JSContext* cx, size_t lineno, Vector<uint32_t>* offsets) DebugState::getLineOffsets(JSContext* cx, size_t lineno, Vector<uint32_t>* offsets)
{ {
if (!debugEnabled()) if (!metadata_->debugEnabled)
return true; return true;
if (!ensureSourceMap(cx)) if (!ensureSourceMap(cx))
@ -197,7 +190,7 @@ bool
DebugState::getOffsetLocation(JSContext* cx, uint32_t offset, bool* found, size_t* lineno, size_t* column) DebugState::getOffsetLocation(JSContext* cx, uint32_t offset, bool* found, size_t* lineno, size_t* column)
{ {
*found = false; *found = false;
if (!debugEnabled()) if (!metadata_->debugEnabled)
return true; return true;
if (!ensureSourceMap(cx)) if (!ensureSourceMap(cx))
@ -221,7 +214,7 @@ bool
DebugState::totalSourceLines(JSContext* cx, uint32_t* count) DebugState::totalSourceLines(JSContext* cx, uint32_t* count)
{ {
*count = 0; *count = 0;
if (!debugEnabled()) if (!metadata_->debugEnabled)
return true; return true;
if (!ensureSourceMap(cx)) if (!ensureSourceMap(cx))
@ -241,8 +234,8 @@ DebugState::stepModeEnabled(uint32_t funcIndex) const
bool bool
DebugState::incrementStepModeCount(JSContext* cx, uint32_t funcIndex) DebugState::incrementStepModeCount(JSContext* cx, uint32_t funcIndex)
{ {
MOZ_ASSERT(debugEnabled()); MOZ_ASSERT(metadata_->debugEnabled);
const CodeRange& codeRange = codeRanges()[debugFuncToCodeRange(funcIndex)]; const CodeRange& codeRange = metadata_->codeRanges[metadata_->debugFuncToCodeRange[funcIndex]];
MOZ_ASSERT(codeRange.isFunction()); MOZ_ASSERT(codeRange.isFunction());
if (!stepModeCounters_.initialized() && !stepModeCounters_.init()) { if (!stepModeCounters_.initialized() && !stepModeCounters_.init()) {
@ -265,7 +258,7 @@ DebugState::incrementStepModeCount(JSContext* cx, uint32_t funcIndex)
codeRange.end() - codeRange.begin()); codeRange.end() - codeRange.begin());
AutoFlushICache afc("Code::incrementStepModeCount"); AutoFlushICache afc("Code::incrementStepModeCount");
for (const CallSite& callSite : callSites()) { for (const CallSite& callSite : metadata_->callSites) {
if (callSite.kind() != CallSite::Breakpoint) if (callSite.kind() != CallSite::Breakpoint)
continue; continue;
uint32_t offset = callSite.returnAddressOffset(); uint32_t offset = callSite.returnAddressOffset();
@ -278,8 +271,8 @@ DebugState::incrementStepModeCount(JSContext* cx, uint32_t funcIndex)
bool bool
DebugState::decrementStepModeCount(JSContext* cx, uint32_t funcIndex) DebugState::decrementStepModeCount(JSContext* cx, uint32_t funcIndex)
{ {
MOZ_ASSERT(debugEnabled()); MOZ_ASSERT(metadata_->debugEnabled);
const CodeRange& codeRange = codeRanges()[debugFuncToCodeRange(funcIndex)]; const CodeRange& codeRange = metadata_->codeRanges[metadata_->debugFuncToCodeRange[funcIndex]];
MOZ_ASSERT(codeRange.isFunction()); MOZ_ASSERT(codeRange.isFunction());
MOZ_ASSERT(stepModeCounters_.initialized() && !stepModeCounters_.empty()); MOZ_ASSERT(stepModeCounters_.initialized() && !stepModeCounters_.empty());
@ -294,7 +287,7 @@ DebugState::decrementStepModeCount(JSContext* cx, uint32_t funcIndex)
codeRange.end() - codeRange.begin()); codeRange.end() - codeRange.begin());
AutoFlushICache afc("Code::decrementStepModeCount"); AutoFlushICache afc("Code::decrementStepModeCount");
for (const CallSite& callSite : callSites()) { for (const CallSite& callSite : metadata_->callSites) {
if (callSite.kind() != CallSite::Breakpoint) if (callSite.kind() != CallSite::Breakpoint)
continue; continue;
uint32_t offset = callSite.returnAddressOffset(); uint32_t offset = callSite.returnAddressOffset();
@ -319,16 +312,16 @@ SlowCallSiteSearchByOffset(const Metadata& metadata, uint32_t offset)
bool bool
DebugState::hasBreakpointTrapAtOffset(uint32_t offset) DebugState::hasBreakpointTrapAtOffset(uint32_t offset)
{ {
if (!debugEnabled()) if (!metadata_->debugEnabled)
return false; return false;
return SlowCallSiteSearchByOffset(metadata(), offset); return SlowCallSiteSearchByOffset(*metadata_, offset);
} }
void void
DebugState::toggleBreakpointTrap(JSRuntime* rt, uint32_t offset, bool enabled) DebugState::toggleBreakpointTrap(JSRuntime* rt, uint32_t offset, bool enabled)
{ {
MOZ_ASSERT(debugEnabled()); MOZ_ASSERT(metadata_->debugEnabled);
const CallSite* callSite = SlowCallSiteSearchByOffset(metadata(), offset); const CallSite* callSite = SlowCallSiteSearchByOffset(*metadata_, offset);
if (!callSite) if (!callSite)
return; return;
size_t debugTrapOffset = callSite->returnAddressOffset(); size_t debugTrapOffset = callSite->returnAddressOffset();
@ -420,7 +413,7 @@ DebugState::toggleDebugTrap(uint32_t offset, bool enabled)
{ {
MOZ_ASSERT(offset); MOZ_ASSERT(offset);
uint8_t* trap = code_->segment().base() + offset; uint8_t* trap = code_->segment().base() + offset;
const Uint32Vector& farJumpOffsets = metadata().debugTrapFarJumpOffsets; const Uint32Vector& farJumpOffsets = metadata_->debugTrapFarJumpOffsets;
if (enabled) { if (enabled) {
MOZ_ASSERT(farJumpOffsets.length() > 0); MOZ_ASSERT(farJumpOffsets.length() > 0);
size_t i = 0; size_t i = 0;
@ -439,7 +432,7 @@ DebugState::toggleDebugTrap(uint32_t offset, bool enabled)
void void
DebugState::adjustEnterAndLeaveFrameTrapsState(JSContext* cx, bool enabled) DebugState::adjustEnterAndLeaveFrameTrapsState(JSContext* cx, bool enabled)
{ {
MOZ_ASSERT(debugEnabled()); MOZ_ASSERT(metadata_->debugEnabled);
MOZ_ASSERT_IF(!enabled, enterAndLeaveFrameTrapsCounter_ > 0); MOZ_ASSERT_IF(!enabled, enterAndLeaveFrameTrapsCounter_ > 0);
bool wasEnabled = enterAndLeaveFrameTrapsCounter_ > 0; bool wasEnabled = enterAndLeaveFrameTrapsCounter_ > 0;
@ -454,7 +447,7 @@ DebugState::adjustEnterAndLeaveFrameTrapsState(JSContext* cx, bool enabled)
AutoWritableJitCode awjc(cx->runtime(), code_->segment().base(), code_->segment().length()); AutoWritableJitCode awjc(cx->runtime(), code_->segment().base(), code_->segment().length());
AutoFlushICache afc("Code::adjustEnterAndLeaveFrameTrapsState"); AutoFlushICache afc("Code::adjustEnterAndLeaveFrameTrapsState");
AutoFlushICache::setRange(uintptr_t(code_->segment().base()), code_->segment().length()); AutoFlushICache::setRange(uintptr_t(code_->segment().base()), code_->segment().length());
for (const CallSite& callSite : callSites()) { for (const CallSite& callSite : metadata_->callSites) {
if (callSite.kind() != CallSite::EnterFrame && callSite.kind() != CallSite::LeaveFrame) if (callSite.kind() != CallSite::EnterFrame && callSite.kind() != CallSite::LeaveFrame)
continue; continue;
toggleDebugTrap(callSite.returnAddressOffset(), stillEnabled); toggleDebugTrap(callSite.returnAddressOffset(), stillEnabled);
@ -464,28 +457,28 @@ DebugState::adjustEnterAndLeaveFrameTrapsState(JSContext* cx, bool enabled)
bool bool
DebugState::debugGetLocalTypes(uint32_t funcIndex, ValTypeVector* locals, size_t* argsLength) DebugState::debugGetLocalTypes(uint32_t funcIndex, ValTypeVector* locals, size_t* argsLength)
{ {
MOZ_ASSERT(debugEnabled()); MOZ_ASSERT(metadata_->debugEnabled);
const ValTypeVector& args = metadata().debugFuncArgTypes[funcIndex]; const ValTypeVector& args = metadata_->debugFuncArgTypes[funcIndex];
*argsLength = args.length(); *argsLength = args.length();
if (!locals->appendAll(args)) if (!locals->appendAll(args))
return false; return false;
// Decode local var types from wasm binary function body. // Decode local var types from wasm binary function body.
const CodeRange& range = codeRanges()[debugFuncToCodeRange(funcIndex)]; const CodeRange& range = metadata_->codeRanges[metadata_->debugFuncToCodeRange[funcIndex]];
// In wasm, the Code points to the function start via funcLineOrBytecode. // In wasm, the Code points to the function start via funcLineOrBytecode.
MOZ_ASSERT(!metadata().isAsmJS() && maybeBytecode_); MOZ_ASSERT(!metadata_->isAsmJS() && maybeBytecode_);
size_t offsetInModule = range.funcLineOrBytecode(); size_t offsetInModule = range.funcLineOrBytecode();
Decoder d(maybeBytecode_->begin() + offsetInModule, maybeBytecode_->end(), Decoder d(maybeBytecode_->begin() + offsetInModule, maybeBytecode_->end(),
offsetInModule, /* error = */ nullptr); offsetInModule, /* error = */ nullptr);
return DecodeLocalEntries(d, metadata().kind, locals); return DecodeLocalEntries(d, metadata_->kind, locals);
} }
ExprType ExprType
DebugState::debugGetResultType(uint32_t funcIndex) DebugState::debugGetResultType(uint32_t funcIndex)
{ {
MOZ_ASSERT(debugEnabled()); MOZ_ASSERT(metadata_->debugEnabled);
return metadata().debugFuncReturnTypes[funcIndex]; return metadata_->debugFuncReturnTypes[funcIndex];
} }
JSString* JSString*
@ -498,7 +491,7 @@ DebugState::debugDisplayURL(JSContext* cx) const
js::StringBuffer result(cx); js::StringBuffer result(cx);
if (!result.append("wasm:")) if (!result.append("wasm:"))
return nullptr; return nullptr;
if (const char* filename = metadata().filename.get()) { if (const char* filename = metadata_->filename.get()) {
js::StringBuffer filenamePrefix(cx); js::StringBuffer filenamePrefix(cx);
// EncodeURI returns false due to invalid chars or OOM -- fail only // EncodeURI returns false due to invalid chars or OOM -- fail only
// during OOM. // during OOM.
@ -511,7 +504,7 @@ DebugState::debugDisplayURL(JSContext* cx) const
} }
} }
const ModuleHash& hash = metadata().hash; const ModuleHash& hash = metadata_->hash;
for (size_t i = 0; i < sizeof(ModuleHash); i++) { for (size_t i = 0; i < sizeof(ModuleHash); i++) {
char digit1 = hash[i] / 16, digit2 = hash[i] % 16; char digit1 = hash[i] / 16, digit2 = hash[i] % 16;
if (!result.append((char)(digit1 < 10 ? digit1 + '0' : digit1 + 'a' - 10))) if (!result.append((char)(digit1 < 10 ? digit1 + '0' : digit1 + 'a' - 10)))
@ -520,19 +513,5 @@ DebugState::debugDisplayURL(JSContext* cx) const
return nullptr; return nullptr;
} }
return result.finishString(); return result.finishString();
}
void
DebugState::addSizeOfMisc(MallocSizeOf mallocSizeOf,
Metadata::SeenSet* seenMetadata,
ShareableBytes::SeenSet* seenBytes,
Code::SeenSet* seenCode,
size_t* code,
size_t* data) const
{
code_->addSizeOfMiscIfNotSeen(mallocSizeOf, seenMetadata, seenBytes, seenCode, code, data);
if (maybeSourceMap_)
*data += maybeSourceMap_->sizeOfExcludingThis(mallocSizeOf);
if (maybeBytecode_)
*data += maybeBytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
} }

Просмотреть файл

@ -71,8 +71,6 @@ class GeneratedSourceMap
void setTotalLines(uint32_t val) { totalLines_ = val; } void setTotalLines(uint32_t val) { totalLines_ = val; }
bool searchLineByOffset(JSContext* cx, uint32_t offset, size_t* exprlocIndex); bool searchLineByOffset(JSContext* cx, uint32_t offset, size_t* exprlocIndex);
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
}; };
typedef UniquePtr<GeneratedSourceMap> UniqueGeneratedSourceMap; typedef UniquePtr<GeneratedSourceMap> UniqueGeneratedSourceMap;
@ -82,6 +80,7 @@ typedef HashMap<uint32_t, WasmBreakpointSite*, DefaultHasher<uint32_t>, SystemAl
class DebugState class DebugState
{ {
const SharedCode code_; const SharedCode code_;
const SharedMetadata metadata_;
const SharedBytes maybeBytecode_; const SharedBytes maybeBytecode_;
UniqueGeneratedSourceMap maybeSourceMap_; UniqueGeneratedSourceMap maybeSourceMap_;
@ -98,6 +97,7 @@ class DebugState
public: public:
DebugState(SharedCode code, DebugState(SharedCode code,
const Metadata& metadata,
const ShareableBytes* maybeBytecode); const ShareableBytes* maybeBytecode);
// If the source bytecode was saved when this Code was constructed, this // If the source bytecode was saved when this Code was constructed, this
@ -140,26 +140,6 @@ class DebugState
// Debug URL helpers. // Debug URL helpers.
JSString* debugDisplayURL(JSContext* cx) const; JSString* debugDisplayURL(JSContext* cx) const;
// Accessors for commonly used elements of linked structures.
const Metadata& metadata() const { return code_->metadata(); }
bool debugEnabled() const { return metadata().debugEnabled; }
const CodeRangeVector& codeRanges() const { return metadata().codeRanges; }
const CallSiteVector& callSites() const { return metadata().callSites; }
uint32_t debugFuncToCodeRange(uint32_t funcIndex) const {
return metadata().debugFuncToCodeRange[funcIndex];
}
// about:memory reporting:
void addSizeOfMisc(MallocSizeOf mallocSizeOf,
Metadata::SeenSet* seenMetadata,
ShareableBytes::SeenSet* seenBytes,
Code::SeenSet* seenCode,
size_t* code,
size_t* data) const;
}; };
typedef UniquePtr<DebugState> UniqueDebugState; typedef UniquePtr<DebugState> UniqueDebugState;

Просмотреть файл

@ -1124,6 +1124,25 @@ ModuleGenerator::finish(const ShareableBytes& bytecode)
if (!finishCodegen()) if (!finishCodegen())
return nullptr; return nullptr;
// Round up the code size to page size since this is eventually required by
// the executable-code allocator and for setting memory protection.
uint32_t bytesNeeded = masm_.bytesNeeded();
uint32_t padding = ComputeByteAlignment(bytesNeeded, gc::SystemPageSize());
// Use initLengthUninitialized so there is no round-up allocation nor time
// wasted zeroing memory.
Bytes code;
if (!code.initLengthUninitialized(bytesNeeded + padding))
return nullptr;
// We're not copying into executable memory, so don't flush the icache.
// Note: we may be executing on an arbitrary thread without TlsContext set
// so we can't use AutoFlushICache to inhibit.
masm_.executableCopy(code.begin(), /* flushICache = */ false);
// Zero the padding, since we used resizeUninitialized above.
memset(code.begin() + bytesNeeded, 0, padding);
// Convert the CallSiteAndTargetVector (needed during generation) to a // Convert the CallSiteAndTargetVector (needed during generation) to a
// CallSiteVector (what is stored in the Module). // CallSiteVector (what is stored in the Module).
if (!metadata_->callSites.appendAll(masm_.callSites())) if (!metadata_->callSites.appendAll(masm_.callSites()))
@ -1183,29 +1202,14 @@ ModuleGenerator::finish(const ShareableBytes& bytecode)
generateBytecodeHash(bytecode); generateBytecodeHash(bytecode);
UniqueConstCodeSegment codeSegment = CodeSegment::create(masm_, bytecode, linkData_, *metadata_);
if (!codeSegment)
return nullptr;
UniqueConstBytes maybeDebuggingBytes;
if (metadata_->debugEnabled) {
maybeDebuggingBytes = codeSegment->unlinkedBytesForDebugging(linkData_);
if (!maybeDebuggingBytes)
return nullptr;
}
SharedCode code = js_new<Code>(Move(codeSegment), *metadata_, &bytecode);
if (!code)
return nullptr;
return SharedModule(js_new<Module>(Move(assumptions_), return SharedModule(js_new<Module>(Move(assumptions_),
*code, Move(code),
Move(maybeDebuggingBytes),
Move(linkData_), Move(linkData_),
Move(env_->imports), Move(env_->imports),
Move(env_->exports), Move(env_->exports),
Move(env_->dataSegments), Move(env_->dataSegments),
Move(env_->elemSegments), Move(env_->elemSegments),
*metadata_,
bytecode)); bytecode));
} }

Просмотреть файл

@ -802,15 +802,13 @@ void
Instance::addSizeOfMisc(MallocSizeOf mallocSizeOf, Instance::addSizeOfMisc(MallocSizeOf mallocSizeOf,
Metadata::SeenSet* seenMetadata, Metadata::SeenSet* seenMetadata,
ShareableBytes::SeenSet* seenBytes, ShareableBytes::SeenSet* seenBytes,
Code::SeenSet* seenCode,
Table::SeenSet* seenTables, Table::SeenSet* seenTables,
size_t* code, size_t* code,
size_t* data) const size_t* data) const
{ {
*data += mallocSizeOf(this) + globals_->sizeOfMisc(mallocSizeOf); *data += mallocSizeOf(this) + globals_->sizeOfMisc(mallocSizeOf);
debug_->addSizeOfMisc(mallocSizeOf, seenMetadata, seenBytes, seenCode, code, data);
code_->addSizeOfMiscIfNotSeen(mallocSizeOf, seenMetadata, seenBytes, seenCode, code, data); code_->addSizeOfMisc(mallocSizeOf, seenMetadata, seenBytes, code, data);
for (const SharedTable& table : tables_) for (const SharedTable& table : tables_)
*data += table->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenTables); *data += table->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenTables);

Просмотреть файл

@ -62,10 +62,6 @@ typedef UniquePtr<GlobalSegment> UniqueGlobalSegment;
// instances instantiated from the same Module. However, an Instance has no // instances instantiated from the same Module. However, an Instance has no
// direct reference to its source Module which allows a Module to be destroyed // direct reference to its source Module which allows a Module to be destroyed
// while it still has live Instances. // while it still has live Instances.
//
// The instance's code may be shared among multiple instances provided none of
// those instances are being debugged. Instances that are being debugged own
// their code.
class Instance class Instance
{ {
@ -162,7 +158,6 @@ class Instance
void addSizeOfMisc(MallocSizeOf mallocSizeOf, void addSizeOfMisc(MallocSizeOf mallocSizeOf,
Metadata::SeenSet* seenMetadata, Metadata::SeenSet* seenMetadata,
ShareableBytes::SeenSet* seenBytes, ShareableBytes::SeenSet* seenBytes,
Code::SeenSet* seenCode,
Table::SeenSet* seenTables, Table::SeenSet* seenTables,
size_t* code, size_t* code,
size_t* data) const; size_t* data) const;

Просмотреть файл

@ -815,7 +815,6 @@ WasmModuleObject::create(JSContext* cx, Module& module, HandleObject proto)
obj->initReservedSlot(MODULE_SLOT, PrivateValue(&module)); obj->initReservedSlot(MODULE_SLOT, PrivateValue(&module));
module.AddRef(); module.AddRef();
cx->zone()->updateJitCodeMallocBytes(module.codeLength());
return obj; return obj;
} }

Просмотреть файл

@ -146,17 +146,18 @@ Module::serializedSize(size_t* maybeBytecodeSize, size_t* maybeCompiledSize) con
// The compiled debug code must not be saved, set compiled size to 0, // The compiled debug code must not be saved, set compiled size to 0,
// so Module::assumptionsMatch will return false during assumptions // so Module::assumptionsMatch will return false during assumptions
// deserialization. // deserialization.
if (maybeCompiledSize && metadata().debugEnabled) if (maybeCompiledSize && metadata_->debugEnabled)
*maybeCompiledSize = 0; *maybeCompiledSize = 0;
if (maybeCompiledSize && !metadata().debugEnabled) { if (maybeCompiledSize && !metadata_->debugEnabled) {
*maybeCompiledSize = assumptions_.serializedSize() + *maybeCompiledSize = assumptions_.serializedSize() +
SerializedPodVectorSize(code_) +
linkData_.serializedSize() + linkData_.serializedSize() +
SerializedVectorSize(imports_) + SerializedVectorSize(imports_) +
SerializedVectorSize(exports_) + SerializedVectorSize(exports_) +
SerializedPodVectorSize(dataSegments_) + SerializedPodVectorSize(dataSegments_) +
SerializedVectorSize(elemSegments_) + SerializedVectorSize(elemSegments_) +
code_->serializedSize(); metadata_->serializedSize();
} }
} }
@ -179,21 +180,22 @@ Module::serialize(uint8_t* maybeBytecodeBegin, size_t maybeBytecodeSize,
MOZ_RELEASE_ASSERT(bytecodeEnd == maybeBytecodeBegin + maybeBytecodeSize); MOZ_RELEASE_ASSERT(bytecodeEnd == maybeBytecodeBegin + maybeBytecodeSize);
} }
MOZ_ASSERT_IF(maybeCompiledBegin && metadata().debugEnabled, maybeCompiledSize == 0); MOZ_ASSERT_IF(maybeCompiledBegin && metadata_->debugEnabled, maybeCompiledSize == 0);
if (maybeCompiledBegin && !metadata().debugEnabled) { if (maybeCompiledBegin && !metadata_->debugEnabled) {
// Assumption must be serialized at the beginning of the compiled bytes so // Assumption must be serialized at the beginning of the compiled bytes so
// that compiledAssumptionsMatch can detect a build-id mismatch before any // that compiledAssumptionsMatch can detect a build-id mismatch before any
// other decoding occurs. // other decoding occurs.
uint8_t* cursor = maybeCompiledBegin; uint8_t* cursor = maybeCompiledBegin;
cursor = assumptions_.serialize(cursor); cursor = assumptions_.serialize(cursor);
cursor = SerializePodVector(cursor, code_);
cursor = linkData_.serialize(cursor); cursor = linkData_.serialize(cursor);
cursor = SerializeVector(cursor, imports_); cursor = SerializeVector(cursor, imports_);
cursor = SerializeVector(cursor, exports_); cursor = SerializeVector(cursor, exports_);
cursor = SerializePodVector(cursor, dataSegments_); cursor = SerializePodVector(cursor, dataSegments_);
cursor = SerializeVector(cursor, elemSegments_); cursor = SerializeVector(cursor, elemSegments_);
cursor = code_->serialize(cursor, linkData_); cursor = metadata_->serialize(cursor);
MOZ_RELEASE_ASSERT(cursor == maybeCompiledBegin + maybeCompiledSize); MOZ_RELEASE_ASSERT(cursor == maybeCompiledBegin + maybeCompiledSize);
} }
} }
@ -224,6 +226,11 @@ Module::deserialize(const uint8_t* bytecodeBegin, size_t bytecodeSize,
if (!cursor) if (!cursor)
return nullptr; return nullptr;
Bytes code;
cursor = DeserializePodVector(cursor, &code);
if (!cursor)
return nullptr;
LinkData linkData; LinkData linkData;
cursor = linkData.deserialize(cursor); cursor = linkData.deserialize(cursor);
if (!cursor) if (!cursor)
@ -249,22 +256,29 @@ Module::deserialize(const uint8_t* bytecodeBegin, size_t bytecodeSize,
if (!cursor) if (!cursor)
return nullptr; return nullptr;
MutableCode code = js_new<Code>(); MutableMetadata metadata;
cursor = code->deserialize(cursor, bytecode, linkData, maybeMetadata); if (maybeMetadata) {
metadata = maybeMetadata;
} else {
metadata = js_new<Metadata>();
if (!metadata)
return nullptr;
}
cursor = metadata->deserialize(cursor);
if (!cursor) if (!cursor)
return nullptr; return nullptr;
MOZ_RELEASE_ASSERT(cursor == compiledBegin + compiledSize); MOZ_RELEASE_ASSERT(cursor == compiledBegin + compiledSize);
MOZ_RELEASE_ASSERT(!!maybeMetadata == code->metadata().isAsmJS()); MOZ_RELEASE_ASSERT(!!maybeMetadata == metadata->isAsmJS());
return js_new<Module>(Move(assumptions), return js_new<Module>(Move(assumptions),
*code, Move(code),
nullptr, // Serialized code is never debuggable
Move(linkData), Move(linkData),
Move(imports), Move(imports),
Move(exports), Move(exports),
Move(dataSegments), Move(dataSegments),
Move(elemSegments), Move(elemSegments),
*metadata,
*bytecode); *bytecode);
} }
@ -363,21 +377,19 @@ wasm::DeserializeModule(PRFileDesc* bytecodeFile, PRFileDesc* maybeCompiledFile,
Module::addSizeOfMisc(MallocSizeOf mallocSizeOf, Module::addSizeOfMisc(MallocSizeOf mallocSizeOf,
Metadata::SeenSet* seenMetadata, Metadata::SeenSet* seenMetadata,
ShareableBytes::SeenSet* seenBytes, ShareableBytes::SeenSet* seenBytes,
Code::SeenSet* seenCode,
size_t* code, size_t* code,
size_t* data) const size_t* data) const
{ {
code_->addSizeOfMiscIfNotSeen(mallocSizeOf, seenMetadata, seenBytes, seenCode, code, data);
*data += mallocSizeOf(this) + *data += mallocSizeOf(this) +
assumptions_.sizeOfExcludingThis(mallocSizeOf) + assumptions_.sizeOfExcludingThis(mallocSizeOf) +
code_.sizeOfExcludingThis(mallocSizeOf) +
linkData_.sizeOfExcludingThis(mallocSizeOf) + linkData_.sizeOfExcludingThis(mallocSizeOf) +
SizeOfVectorExcludingThis(imports_, mallocSizeOf) + SizeOfVectorExcludingThis(imports_, mallocSizeOf) +
SizeOfVectorExcludingThis(exports_, mallocSizeOf) + SizeOfVectorExcludingThis(exports_, mallocSizeOf) +
dataSegments_.sizeOfExcludingThis(mallocSizeOf) + dataSegments_.sizeOfExcludingThis(mallocSizeOf) +
SizeOfVectorExcludingThis(elemSegments_, mallocSizeOf) + SizeOfVectorExcludingThis(elemSegments_, mallocSizeOf) +
metadata_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenMetadata) +
bytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes); bytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
if (unlinkedCodeForDebugging_)
*data += unlinkedCodeForDebugging_->sizeOfExcludingThis(mallocSizeOf);
} }
@ -386,17 +398,17 @@ Module::addSizeOfMisc(MallocSizeOf mallocSizeOf,
// contain offsets in the "code" array and basic information about a code // contain offsets in the "code" array and basic information about a code
// segment/function body. // segment/function body.
bool bool
Module::extractCode(JSContext* cx, MutableHandleValue vp) const Module::extractCode(JSContext* cx, MutableHandleValue vp)
{ {
RootedPlainObject result(cx, NewBuiltinClassInstance<PlainObject>(cx)); RootedPlainObject result(cx, NewBuiltinClassInstance<PlainObject>(cx));
if (!result) if (!result)
return false; return false;
RootedObject code(cx, JS_NewUint8Array(cx, code_->segment().length())); RootedObject code(cx, JS_NewUint8Array(cx, code_.length()));
if (!code) if (!code)
return false; return false;
memcpy(code->as<TypedArrayObject>().viewDataUnshared(), code_->segment().base(), code_->segment().length()); memcpy(code->as<TypedArrayObject>().viewDataUnshared(), code_.begin(), code_.length());
RootedValue value(cx, ObjectValue(*code)); RootedValue value(cx, ObjectValue(*code));
if (!JS_DefineProperty(cx, result, "code", value, JSPROP_ENUMERATE)) if (!JS_DefineProperty(cx, result, "code", value, JSPROP_ENUMERATE))
@ -406,7 +418,7 @@ Module::extractCode(JSContext* cx, MutableHandleValue vp) const
if (!segments) if (!segments)
return false; return false;
for (const CodeRange& p : metadata().codeRanges) { for (const CodeRange& p : metadata_->codeRanges) {
RootedObject segment(cx, NewObjectWithGivenProto<PlainObject>(cx, nullptr)); RootedObject segment(cx, NewObjectWithGivenProto<PlainObject>(cx, nullptr));
if (!segment) if (!segment)
return false; return false;
@ -563,12 +575,12 @@ FindImportForFuncImport(const ImportVector& imports, uint32_t funcImportIndex)
bool bool
Module::instantiateFunctions(JSContext* cx, Handle<FunctionVector> funcImports) const Module::instantiateFunctions(JSContext* cx, Handle<FunctionVector> funcImports) const
{ {
MOZ_ASSERT(funcImports.length() == metadata().funcImports.length()); MOZ_ASSERT(funcImports.length() == metadata_->funcImports.length());
if (metadata().isAsmJS()) if (metadata().isAsmJS())
return true; return true;
for (size_t i = 0; i < metadata().funcImports.length(); i++) { for (size_t i = 0; i < metadata_->funcImports.length(); i++) {
HandleFunction f = funcImports[i]; HandleFunction f = funcImports[i];
if (!IsExportedFunction(f) || ExportedFunctionToInstance(f).isAsmJS()) if (!IsExportedFunction(f) || ExportedFunctionToInstance(f).isAsmJS())
continue; continue;
@ -577,7 +589,7 @@ Module::instantiateFunctions(JSContext* cx, Handle<FunctionVector> funcImports)
Instance& instance = ExportedFunctionToInstance(f); Instance& instance = ExportedFunctionToInstance(f);
const FuncExport& funcExport = instance.metadata().lookupFuncExport(funcIndex); const FuncExport& funcExport = instance.metadata().lookupFuncExport(funcIndex);
if (funcExport.sig() != metadata().funcImports[i].sig()) { if (funcExport.sig() != metadata_->funcImports[i].sig()) {
const Import& import = FindImportForFuncImport(imports_, i); const Import& import = FindImportForFuncImport(imports_, i);
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMPORT_SIG, JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMPORT_SIG,
import.module.get(), import.field.get()); import.module.get(), import.field.get());
@ -618,27 +630,27 @@ CheckLimits(JSContext* cx, uint32_t declaredMin, const Maybe<uint32_t>& declared
bool bool
Module::instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) const Module::instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) const
{ {
if (!metadata().usesMemory()) { if (!metadata_->usesMemory()) {
MOZ_ASSERT(!memory); MOZ_ASSERT(!memory);
MOZ_ASSERT(dataSegments_.empty()); MOZ_ASSERT(dataSegments_.empty());
return true; return true;
} }
uint32_t declaredMin = metadata().minMemoryLength; uint32_t declaredMin = metadata_->minMemoryLength;
Maybe<uint32_t> declaredMax = metadata().maxMemoryLength; Maybe<uint32_t> declaredMax = metadata_->maxMemoryLength;
if (memory) { if (memory) {
ArrayBufferObjectMaybeShared& buffer = memory->buffer(); ArrayBufferObjectMaybeShared& buffer = memory->buffer();
MOZ_ASSERT_IF(metadata().isAsmJS(), buffer.isPreparedForAsmJS()); MOZ_ASSERT_IF(metadata_->isAsmJS(), buffer.isPreparedForAsmJS());
MOZ_ASSERT_IF(!metadata().isAsmJS(), buffer.as<ArrayBufferObject>().isWasm()); MOZ_ASSERT_IF(!metadata_->isAsmJS(), buffer.as<ArrayBufferObject>().isWasm());
if (!CheckLimits(cx, declaredMin, declaredMax, buffer.byteLength(), buffer.wasmMaxSize(), if (!CheckLimits(cx, declaredMin, declaredMax, buffer.byteLength(), buffer.wasmMaxSize(),
metadata().isAsmJS(), "Memory")) { metadata_->isAsmJS(), "Memory")) {
return false; return false;
} }
} else { } else {
MOZ_ASSERT(!metadata().isAsmJS()); MOZ_ASSERT(!metadata_->isAsmJS());
MOZ_ASSERT(metadata().memoryUsage == MemoryUsage::Unshared); MOZ_ASSERT(metadata_->memoryUsage == MemoryUsage::Unshared);
RootedArrayBufferObjectMaybeShared buffer(cx, RootedArrayBufferObjectMaybeShared buffer(cx,
ArrayBufferObject::createForWasm(cx, declaredMin, declaredMax)); ArrayBufferObject::createForWasm(cx, declaredMin, declaredMax));
@ -660,15 +672,15 @@ Module::instantiateTable(JSContext* cx, MutableHandleWasmTableObject tableObj,
SharedTableVector* tables) const SharedTableVector* tables) const
{ {
if (tableObj) { if (tableObj) {
MOZ_ASSERT(!metadata().isAsmJS()); MOZ_ASSERT(!metadata_->isAsmJS());
MOZ_ASSERT(metadata().tables.length() == 1); MOZ_ASSERT(metadata_->tables.length() == 1);
const TableDesc& td = metadata().tables[0]; const TableDesc& td = metadata_->tables[0];
MOZ_ASSERT(td.external); MOZ_ASSERT(td.external);
Table& table = tableObj->table(); Table& table = tableObj->table();
if (!CheckLimits(cx, td.limits.initial, td.limits.maximum, table.length(), table.maximum(), if (!CheckLimits(cx, td.limits.initial, td.limits.maximum, table.length(), table.maximum(),
metadata().isAsmJS(), "Table")) { metadata_->isAsmJS(), "Table")) {
return false; return false;
} }
@ -677,7 +689,7 @@ Module::instantiateTable(JSContext* cx, MutableHandleWasmTableObject tableObj,
return false; return false;
} }
} else { } else {
for (const TableDesc& td : metadata().tables) { for (const TableDesc& td : metadata_->tables) {
SharedTable table; SharedTable table;
if (td.external) { if (td.external) {
MOZ_ASSERT(!tableObj); MOZ_ASSERT(!tableObj);
@ -869,29 +881,16 @@ Module::instantiate(JSContext* cx,
if (!instantiateTable(cx, &table, &tables)) if (!instantiateTable(cx, &table, &tables))
return false; return false;
// The CodeSegment does not hold on to the bytecode, see comment below.
auto codeSegment = CodeSegment::create(cx, code_, bytecode_, linkData_, *metadata_);
if (!codeSegment)
return false;
auto globalSegment = GlobalSegment::create(linkData_.globalDataLength); auto globalSegment = GlobalSegment::create(linkData_.globalDataLength);
if (!globalSegment) if (!globalSegment)
return false; return false;
SharedCode code(code_);
if (metadata().debugEnabled) {
// The first time through, use the pre-linked code in the module but
// mark it as busy. Subsequently, instantiate the copy of the code
// bytes that we keep around for debugging instead, because the debugger
// may patch the pre-linked code at any time.
if (!codeIsBusy_.compareExchange(false, true)) {
UniqueConstCodeSegment codeSegment = CodeSegment::create(*unlinkedCodeForDebugging_,
*bytecode_, linkData_,
metadata());
if (!codeSegment)
return false;
code = js_new<Code>(Move(codeSegment), metadata(), bytecode_);
if (!code)
return false;
}
}
// To support viewing the source of an instance (Instance::createText), the // To support viewing the source of an instance (Instance::createText), the
// instance must hold onto a ref of the bytecode (keeping it alive). This // instance must hold onto a ref of the bytecode (keeping it alive). This
// wastes memory for most users, so we try to only save the source when a // wastes memory for most users, so we try to only save the source when a
@ -901,17 +900,21 @@ Module::instantiate(JSContext* cx,
// for non-developer builds). // for non-developer builds).
const ShareableBytes* maybeBytecode = nullptr; const ShareableBytes* maybeBytecode = nullptr;
if (cx->compartment()->isDebuggee() || metadata().debugEnabled || if (cx->compartment()->isDebuggee() || metadata_->debugEnabled ||
!metadata().funcNames.empty()) !metadata_->funcNames.empty())
{ {
maybeBytecode = bytecode_.get(); maybeBytecode = bytecode_.get();
} }
SharedCode code(js_new<Code>(Move(codeSegment), *metadata_, maybeBytecode));
if (!code)
return false;
// The debug object must be present even when debugging is not enabled: It // The debug object must be present even when debugging is not enabled: It
// provides the lazily created source text for the program, even if that // provides the lazily created source text for the program, even if that
// text is a placeholder message when debugging is not enabled. // text is a placeholder message when debugging is not enabled.
auto debug = cx->make_unique<DebugState>(code, maybeBytecode); auto debug = cx->make_unique<DebugState>(code, *metadata_, maybeBytecode);
if (!debug) if (!debug)
return false; return false;
@ -959,9 +962,9 @@ Module::instantiate(JSContext* cx,
// Note that failure may cause instantiation to throw, but the instance may // Note that failure may cause instantiation to throw, but the instance may
// still be live via edges created by initSegments or the start function. // still be live via edges created by initSegments or the start function.
if (metadata().startFuncIndex) { if (metadata_->startFuncIndex) {
FixedInvokeArgs<0> args(cx); FixedInvokeArgs<0> args(cx);
if (!instance->instance().callExport(cx, *metadata().startFuncIndex, args)) if (!instance->instance().callExport(cx, *metadata_->startFuncIndex, args))
return false; return false;
} }

Просмотреть файл

@ -83,32 +83,24 @@ typedef UniquePtr<const LinkData> UniqueConstLinkData;
// any number of times such that the serialized bytes can be deserialized later // any number of times such that the serialized bytes can be deserialized later
// to produce a new, equivalent Module. // to produce a new, equivalent Module.
// //
// Fully linked-and-instantiated code (represented by Code and its owned // Since fully linked-and-instantiated code (represented by CodeSegment) cannot
// CodeSegment) can be shared between instances, provided none of those // be shared between instances, Module stores an unlinked, uninstantiated copy
// instances are being debugged. If patchable code is needed then each instance // of the code (represented by the Bytes) and creates a new CodeSegment each
// must have its own Code. Module eagerly creates a new Code and gives it to the // time it is instantiated. In the future, Module will store a shareable,
// first instance; it then instantiates new Code objects from a copy of the // immutable CodeSegment that can be shared by all its instances.
// unlinked code that it keeps around for that purpose.
class Module : public JS::WasmModule class Module : public JS::WasmModule
{ {
const Assumptions assumptions_; const Assumptions assumptions_;
const SharedCode code_; const Bytes code_;
const UniqueConstBytes unlinkedCodeForDebugging_;
const LinkData linkData_; const LinkData linkData_;
const ImportVector imports_; const ImportVector imports_;
const ExportVector exports_; const ExportVector exports_;
const DataSegmentVector dataSegments_; const DataSegmentVector dataSegments_;
const ElemSegmentVector elemSegments_; const ElemSegmentVector elemSegments_;
const SharedMetadata metadata_;
const SharedBytes bytecode_; const SharedBytes bytecode_;
// `codeIsBusy_` is set to false initially and then to true when `code_` is
// already being used for an instance and can't be shared because it may be
// patched by the debugger. Subsequent instances must then create copies
// by linking the `unlinkedCodeForDebugging_`.
mutable mozilla::Atomic<bool> codeIsBusy_;
bool instantiateFunctions(JSContext* cx, Handle<FunctionVector> funcImports) const; bool instantiateFunctions(JSContext* cx, Handle<FunctionVector> funcImports) const;
bool instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) const; bool instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) const;
bool instantiateTable(JSContext* cx, bool instantiateTable(JSContext* cx,
@ -122,34 +114,30 @@ class Module : public JS::WasmModule
public: public:
Module(Assumptions&& assumptions, Module(Assumptions&& assumptions,
const Code& code, Bytes&& code,
UniqueConstBytes unlinkedCodeForDebugging,
LinkData&& linkData, LinkData&& linkData,
ImportVector&& imports, ImportVector&& imports,
ExportVector&& exports, ExportVector&& exports,
DataSegmentVector&& dataSegments, DataSegmentVector&& dataSegments,
ElemSegmentVector&& elemSegments, ElemSegmentVector&& elemSegments,
const Metadata& metadata,
const ShareableBytes& bytecode) const ShareableBytes& bytecode)
: assumptions_(Move(assumptions)), : assumptions_(Move(assumptions)),
code_(&code), code_(Move(code)),
unlinkedCodeForDebugging_(Move(unlinkedCodeForDebugging)),
linkData_(Move(linkData)), linkData_(Move(linkData)),
imports_(Move(imports)), imports_(Move(imports)),
exports_(Move(exports)), exports_(Move(exports)),
dataSegments_(Move(dataSegments)), dataSegments_(Move(dataSegments)),
elemSegments_(Move(elemSegments)), elemSegments_(Move(elemSegments)),
bytecode_(&bytecode), metadata_(&metadata),
codeIsBusy_(false) bytecode_(&bytecode)
{ {}
MOZ_ASSERT_IF(metadata().debugEnabled, unlinkedCodeForDebugging_);
}
~Module() override { /* Note: can be called on any thread */ } ~Module() override { /* Note: can be called on any thread */ }
const Metadata& metadata() const { return code_->metadata(); } const Metadata& metadata() const { return *metadata_; }
const ImportVector& imports() const { return imports_; } const ImportVector& imports() const { return imports_; }
const ExportVector& exports() const { return exports_; } const ExportVector& exports() const { return exports_; }
const Bytes& bytecode() const { return bytecode_->bytes; } const Bytes& bytecode() const { return bytecode_->bytes; }
uint32_t codeLength() const { return code_->segment().length(); }
// Instantiate this module with the given imports: // Instantiate this module with the given imports:
@ -178,12 +166,11 @@ class Module : public JS::WasmModule
void addSizeOfMisc(MallocSizeOf mallocSizeOf, void addSizeOfMisc(MallocSizeOf mallocSizeOf,
Metadata::SeenSet* seenMetadata, Metadata::SeenSet* seenMetadata,
ShareableBytes::SeenSet* seenBytes, ShareableBytes::SeenSet* seenBytes,
Code::SeenSet* seenCode,
size_t* code, size_t* data) const; size_t* code, size_t* data) const;
// Generated code analysis support: // Generated code analysis support:
bool extractCode(JSContext* cx, MutableHandleValue vp) const; bool extractCode(JSContext* cx, MutableHandleValue vp);
}; };
typedef RefPtr<Module> SharedModule; typedef RefPtr<Module> SharedModule;

Просмотреть файл

@ -89,7 +89,6 @@ using mozilla::Unused;
typedef Vector<uint32_t, 0, SystemAllocPolicy> Uint32Vector; typedef Vector<uint32_t, 0, SystemAllocPolicy> Uint32Vector;
typedef Vector<uint8_t, 0, SystemAllocPolicy> Bytes; typedef Vector<uint8_t, 0, SystemAllocPolicy> Bytes;
typedef UniquePtr<Bytes> UniqueBytes; typedef UniquePtr<Bytes> UniqueBytes;
typedef UniquePtr<const Bytes> UniqueConstBytes;
typedef Vector<char, 0, SystemAllocPolicy> UTF8Bytes; typedef Vector<char, 0, SystemAllocPolicy> UTF8Bytes;
typedef int8_t I8x16[16]; typedef int8_t I8x16[16];