LCOV - code coverage report
Current view: top level - js/src/wasm - WasmCode.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 462 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 62 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  *
       4             :  * Copyright 2016 Mozilla Foundation
       5             :  *
       6             :  * Licensed under the Apache License, Version 2.0 (the "License");
       7             :  * you may not use this file except in compliance with the License.
       8             :  * You may obtain a copy of the License at
       9             :  *
      10             :  *     http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  * Unless required by applicable law or agreed to in writing, software
      13             :  * distributed under the License is distributed on an "AS IS" BASIS,
      14             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  * See the License for the specific language governing permissions and
      16             :  * limitations under the License.
      17             :  */
      18             : 
      19             : #include "wasm/WasmCode.h"
      20             : 
      21             : #include "mozilla/BinarySearch.h"
      22             : #include "mozilla/EnumeratedRange.h"
      23             : 
      24             : #include "jit/ExecutableAllocator.h"
      25             : #ifdef JS_ION_PERF
      26             : # include "jit/PerfSpewer.h"
      27             : #endif
      28             : #include "vtune/VTuneWrapper.h"
      29             : #include "wasm/WasmModule.h"
      30             : #include "wasm/WasmSerialize.h"
      31             : 
      32             : #include "jit/MacroAssembler-inl.h"
      33             : 
      34             : using namespace js;
      35             : using namespace js::jit;
      36             : using namespace js::wasm;
      37             : using mozilla::BinarySearch;
      38             : using mozilla::MakeEnumeratedRange;
      39             : using JS::GenericNaN;
      40             : 
      41             : static uint32_t
      42           0 : RoundupCodeLength(uint32_t codeLength)
      43             : {
      44             :     // codeLength is a multiple of the system's page size, but not necessarily
      45             :     // a multiple of ExecutableCodePageSize.
      46           0 :     MOZ_ASSERT(codeLength % gc::SystemPageSize() == 0);
      47           0 :     return JS_ROUNDUP(codeLength, ExecutableCodePageSize);
      48             : }
      49             : 
      50             : /* static */ CodeSegment::UniqueCodeBytes
      51           0 : CodeSegment::AllocateCodeBytes(uint32_t codeLength)
      52             : {
      53           0 :     codeLength = RoundupCodeLength(codeLength);
      54             : 
      55           0 :     void* p = AllocateExecutableMemory(codeLength, ProtectionSetting::Writable);
      56             : 
      57             :     // If the allocation failed and the embedding gives us a last-ditch attempt
      58             :     // to purge all memory (which, in gecko, does a purging GC/CC/GC), do that
      59             :     // then retry the allocation.
      60           0 :     if (!p) {
      61           0 :         if (OnLargeAllocationFailure) {
      62           0 :             OnLargeAllocationFailure();
      63           0 :             p = AllocateExecutableMemory(codeLength, ProtectionSetting::Writable);
      64             :         }
      65             :     }
      66             : 
      67           0 :     if (!p)
      68           0 :         return nullptr;
      69             : 
      70             :     // We account for the bytes allocated in WasmModuleObject::create, where we
      71             :     // have the necessary JSContext.
      72             : 
      73           0 :     return UniqueCodeBytes((uint8_t*)p, FreeCode(codeLength));
      74             : }
      75             : 
      76             : void
      77           0 : CodeSegment::FreeCode::operator()(uint8_t* bytes)
      78             : {
      79           0 :     MOZ_ASSERT(codeLength);
      80           0 :     MOZ_ASSERT(codeLength == RoundupCodeLength(codeLength));
      81             : 
      82             : #ifdef MOZ_VTUNE
      83           0 :     vtune::UnmarkBytes(bytes, codeLength);
      84             : #endif
      85           0 :     DeallocateExecutableMemory(bytes, codeLength);
      86           0 : }
      87             : 
      88             : static bool
      89           0 : StaticallyLink(const CodeSegment& cs, const LinkDataTier& linkData)
      90             : {
      91           0 :     for (LinkDataTier::InternalLink link : linkData.internalLinks) {
      92           0 :         uint8_t* patchAt = cs.base() + link.patchAtOffset;
      93           0 :         void* target = cs.base() + link.targetOffset;
      94           0 :         if (link.isRawPointerPatch())
      95           0 :             *(void**)(patchAt) = target;
      96             :         else
      97           0 :             Assembler::PatchInstructionImmediate(patchAt, PatchedImmPtr(target));
      98             :     }
      99             : 
     100           0 :     if (!EnsureBuiltinThunksInitialized())
     101           0 :         return false;
     102             : 
     103           0 :     for (auto imm : MakeEnumeratedRange(SymbolicAddress::Limit)) {
     104           0 :         const Uint32Vector& offsets = linkData.symbolicLinks[imm];
     105           0 :         if (offsets.empty())
     106           0 :             continue;
     107             : 
     108           0 :         void* target = SymbolicAddressTarget(imm);
     109           0 :         for (uint32_t offset : offsets) {
     110           0 :             uint8_t* patchAt = cs.base() + offset;
     111           0 :             Assembler::PatchDataWithValueCheck(CodeLocationLabel(patchAt),
     112             :                                                PatchedImmPtr(target),
     113           0 :                                                PatchedImmPtr((void*)-1));
     114             :         }
     115             :     }
     116             : 
     117           0 :     return true;
     118             : }
     119             : 
     120             : static void
     121           0 : StaticallyUnlink(uint8_t* base, const LinkDataTier& linkData)
     122             : {
     123           0 :     for (LinkDataTier::InternalLink link : linkData.internalLinks) {
     124           0 :         uint8_t* patchAt = base + link.patchAtOffset;
     125           0 :         void* target = 0;
     126           0 :         if (link.isRawPointerPatch())
     127           0 :             *(void**)(patchAt) = target;
     128             :         else
     129           0 :             Assembler::PatchInstructionImmediate(patchAt, PatchedImmPtr(target));
     130             :     }
     131             : 
     132           0 :     for (auto imm : MakeEnumeratedRange(SymbolicAddress::Limit)) {
     133           0 :         const Uint32Vector& offsets = linkData.symbolicLinks[imm];
     134           0 :         if (offsets.empty())
     135           0 :             continue;
     136             : 
     137           0 :         void* target = SymbolicAddressTarget(imm);
     138           0 :         for (uint32_t offset : offsets) {
     139           0 :             uint8_t* patchAt = base + offset;
     140           0 :             Assembler::PatchDataWithValueCheck(CodeLocationLabel(patchAt),
     141             :                                                PatchedImmPtr((void*)-1),
     142           0 :                                                PatchedImmPtr(target));
     143             :         }
     144             :     }
     145           0 : }
     146             : 
     147             : static void
     148           0 : SendCodeRangesToProfiler(const CodeSegment& cs, const Bytes& bytecode, const Metadata& metadata)
     149             : {
     150           0 :     bool enabled = false;
     151             : #ifdef JS_ION_PERF
     152             :     enabled |= PerfFuncEnabled();
     153             : #endif
     154             : #ifdef MOZ_VTUNE
     155           0 :     enabled |= vtune::IsProfilingActive();
     156             : #endif
     157           0 :     if (!enabled)
     158           0 :         return;
     159             : 
     160           0 :     for (const CodeRange& codeRange : metadata.metadata(cs.tier()).codeRanges) {
     161           0 :         if (!codeRange.isFunction())
     162           0 :             continue;
     163             : 
     164           0 :         uintptr_t start = uintptr_t(cs.base() + codeRange.begin());
     165           0 :         uintptr_t end = uintptr_t(cs.base() + codeRange.end());
     166           0 :         uintptr_t size = end - start;
     167             : 
     168           0 :         UTF8Bytes name;
     169           0 :         if (!metadata.getFuncName(&bytecode, codeRange.funcIndex(), &name))
     170           0 :             return;
     171           0 :         if (!name.append('\0'))
     172           0 :             return;
     173             : 
     174             :         // Avoid "unused" warnings
     175             :         (void)start;
     176             :         (void)size;
     177             : 
     178             : #ifdef JS_ION_PERF
     179             :         if (PerfFuncEnabled()) {
     180             :             const char* file = metadata.filename.get();
     181             :             unsigned line = codeRange.funcLineOrBytecode();
     182             :             unsigned column = 0;
     183             :             writePerfSpewerWasmFunctionMap(start, size, file, line, column, name.begin());
     184             :         }
     185             : #endif
     186             : #ifdef MOZ_VTUNE
     187           0 :         if (vtune::IsProfilingActive())
     188           0 :             vtune::MarkWasm(vtune::GenerateUniqueMethodID(), name.begin(), (void*)start, size);
     189             : #endif
     190             :     }
     191             : 
     192           0 :     return;
     193             : }
     194             : 
     195             : /* static */ UniqueConstCodeSegment
     196           0 : CodeSegment::create(Tier tier,
     197             :                     MacroAssembler& masm,
     198             :                     const ShareableBytes& bytecode,
     199             :                     const LinkDataTier& linkData,
     200             :                     const Metadata& metadata)
     201             : {
     202             :     // Round up the code size to page size since this is eventually required by
     203             :     // the executable-code allocator and for setting memory protection.
     204           0 :     uint32_t bytesNeeded = masm.bytesNeeded();
     205           0 :     uint32_t padding = ComputeByteAlignment(bytesNeeded, gc::SystemPageSize());
     206           0 :     uint32_t codeLength = bytesNeeded + padding;
     207             : 
     208           0 :     MOZ_ASSERT(linkData.functionCodeLength < codeLength);
     209             : 
     210           0 :     UniqueCodeBytes codeBytes = AllocateCodeBytes(codeLength);
     211           0 :     if (!codeBytes)
     212           0 :         return nullptr;
     213             : 
     214             :     // We'll flush the icache after static linking, in initialize().
     215           0 :     masm.executableCopy(codeBytes.get(), /* flushICache = */ false);
     216             : 
     217             :     // Zero the padding.
     218           0 :     memset(codeBytes.get() + bytesNeeded, 0, padding);
     219             : 
     220           0 :     return create(tier, Move(codeBytes), codeLength, bytecode, linkData, metadata);
     221             : }
     222             : 
     223             : /* static */ UniqueConstCodeSegment
     224           0 : CodeSegment::create(Tier tier,
     225             :                     const Bytes& unlinkedBytes,
     226             :                     const ShareableBytes& bytecode,
     227             :                     const LinkDataTier& linkData,
     228             :                     const Metadata& metadata)
     229             : {
     230             :     // The unlinked bytes are a snapshot of the MacroAssembler's contents so
     231             :     // round up just like in the MacroAssembler overload above.
     232           0 :     uint32_t padding = ComputeByteAlignment(unlinkedBytes.length(), gc::SystemPageSize());
     233           0 :     uint32_t codeLength = unlinkedBytes.length() + padding;
     234             : 
     235           0 :     UniqueCodeBytes codeBytes = AllocateCodeBytes(codeLength);
     236           0 :     if (!codeBytes)
     237           0 :         return nullptr;
     238             : 
     239           0 :     memcpy(codeBytes.get(), unlinkedBytes.begin(), unlinkedBytes.length());
     240           0 :     memset(codeBytes.get() + unlinkedBytes.length(), 0, padding);
     241             : 
     242           0 :     return create(tier, Move(codeBytes), codeLength, bytecode, linkData, metadata);
     243             : }
     244             : 
     245             : /* static */ UniqueConstCodeSegment
     246           0 : CodeSegment::create(Tier tier,
     247             :                     UniqueCodeBytes codeBytes,
     248             :                     uint32_t codeLength,
     249             :                     const ShareableBytes& bytecode,
     250             :                     const LinkDataTier& linkData,
     251             :                     const Metadata& metadata)
     252             : {
     253             :     // These should always exist and should never be first in the code segment.
     254           0 :     MOZ_ASSERT(linkData.interruptOffset != 0);
     255           0 :     MOZ_ASSERT(linkData.outOfBoundsOffset != 0);
     256           0 :     MOZ_ASSERT(linkData.unalignedAccessOffset != 0);
     257             : 
     258           0 :     auto cs = js::MakeUnique<CodeSegment>();
     259           0 :     if (!cs)
     260           0 :         return nullptr;
     261             : 
     262           0 :     if (!cs->initialize(tier, Move(codeBytes), codeLength, bytecode, linkData, metadata))
     263           0 :         return nullptr;
     264             : 
     265           0 :     return UniqueConstCodeSegment(cs.release());
     266             : }
     267             : 
     268             : bool
     269           0 : CodeSegment::initialize(Tier tier,
     270             :                         UniqueCodeBytes codeBytes,
     271             :                         uint32_t codeLength,
     272             :                         const ShareableBytes& bytecode,
     273             :                         const LinkDataTier& linkData,
     274             :                         const Metadata& metadata)
     275             : {
     276           0 :     MOZ_ASSERT(bytes_ == nullptr);
     277           0 :     MOZ_ASSERT(tier == Tier::Baseline || tier == Tier::Ion);
     278             : 
     279           0 :     tier_ = tier;
     280           0 :     bytes_ = Move(codeBytes);
     281           0 :     functionLength_ = linkData.functionCodeLength;
     282           0 :     length_ = codeLength;
     283           0 :     interruptCode_ = bytes_.get() + linkData.interruptOffset;
     284           0 :     outOfBoundsCode_ = bytes_.get() + linkData.outOfBoundsOffset;
     285           0 :     unalignedAccessCode_ = bytes_.get() + linkData.unalignedAccessOffset;
     286             : 
     287           0 :     if (!StaticallyLink(*this, linkData))
     288           0 :         return false;
     289             : 
     290           0 :     ExecutableAllocator::cacheFlush(bytes_.get(), RoundupCodeLength(codeLength));
     291             : 
     292             :     // Reprotect the whole region to avoid having separate RW and RX mappings.
     293           0 :     if (!ExecutableAllocator::makeExecutable(bytes_.get(), RoundupCodeLength(codeLength)))
     294           0 :         return false;
     295             : 
     296           0 :     SendCodeRangesToProfiler(*this, bytecode.bytes, metadata);
     297             : 
     298           0 :     return true;
     299             : }
     300             : 
     301             : size_t
     302           0 : CodeSegment::serializedSize() const
     303             : {
     304           0 :     return sizeof(uint32_t) + length_;
     305             : }
     306             : 
     307             : void
     308           0 : CodeSegment::addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t* code, size_t* data) const
     309             : {
     310           0 :     *data += mallocSizeOf(this);
     311           0 :     *code += RoundupCodeLength(length_);
     312           0 : }
     313             : 
     314             : uint8_t*
     315           0 : CodeSegment::serialize(uint8_t* cursor, const LinkDataTier& linkData) const
     316             : {
     317           0 :     MOZ_ASSERT(tier() == Tier::Ion);
     318             : 
     319           0 :     cursor = WriteScalar<uint32_t>(cursor, length_);
     320           0 :     uint8_t* base = cursor;
     321           0 :     cursor = WriteBytes(cursor, bytes_.get(), length_);
     322           0 :     StaticallyUnlink(base, linkData);
     323           0 :     return cursor;
     324             : }
     325             : 
     326             : const uint8_t*
     327           0 : CodeSegment::deserialize(const uint8_t* cursor, const ShareableBytes& bytecode,
     328             :                          const LinkDataTier& linkData, const Metadata& metadata)
     329             : {
     330             :     uint32_t length;
     331           0 :     cursor = ReadScalar<uint32_t>(cursor, &length);
     332           0 :     if (!cursor)
     333           0 :         return nullptr;
     334             : 
     335           0 :     MOZ_ASSERT(length_ % gc::SystemPageSize() == 0);
     336           0 :     UniqueCodeBytes bytes = AllocateCodeBytes(length);
     337           0 :     if (!bytes)
     338           0 :         return nullptr;
     339             : 
     340           0 :     cursor = ReadBytes(cursor, bytes.get(), length);
     341           0 :     if (!cursor)
     342           0 :         return nullptr;
     343             : 
     344           0 :     if (!initialize(Tier::Ion, Move(bytes), length, bytecode, linkData, metadata))
     345           0 :         return nullptr;
     346             : 
     347           0 :     return cursor;
     348             : }
     349             : 
     350             : size_t
     351           0 : FuncExport::serializedSize() const
     352             : {
     353           0 :     return sig_.serializedSize() +
     354           0 :            sizeof(pod);
     355             : }
     356             : 
     357             : uint8_t*
     358           0 : FuncExport::serialize(uint8_t* cursor) const
     359             : {
     360           0 :     cursor = sig_.serialize(cursor);
     361           0 :     cursor = WriteBytes(cursor, &pod, sizeof(pod));
     362           0 :     return cursor;
     363             : }
     364             : 
     365             : const uint8_t*
     366           0 : FuncExport::deserialize(const uint8_t* cursor)
     367             : {
     368           0 :     (cursor = sig_.deserialize(cursor)) &&
     369           0 :     (cursor = ReadBytes(cursor, &pod, sizeof(pod)));
     370           0 :     return cursor;
     371             : }
     372             : 
     373             : size_t
     374           0 : FuncExport::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
     375             : {
     376           0 :     return sig_.sizeOfExcludingThis(mallocSizeOf);
     377             : }
     378             : 
     379             : size_t
     380           0 : FuncImport::serializedSize() const
     381             : {
     382           0 :     return sig_.serializedSize() +
     383           0 :            sizeof(pod);
     384             : }
     385             : 
     386             : uint8_t*
     387           0 : FuncImport::serialize(uint8_t* cursor) const
     388             : {
     389           0 :     cursor = sig_.serialize(cursor);
     390           0 :     cursor = WriteBytes(cursor, &pod, sizeof(pod));
     391           0 :     return cursor;
     392             : }
     393             : 
     394             : const uint8_t*
     395           0 : FuncImport::deserialize(const uint8_t* cursor)
     396             : {
     397           0 :     (cursor = sig_.deserialize(cursor)) &&
     398           0 :     (cursor = ReadBytes(cursor, &pod, sizeof(pod)));
     399           0 :     return cursor;
     400             : }
     401             : 
     402             : size_t
     403           0 : FuncImport::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
     404             : {
     405           0 :     return sig_.sizeOfExcludingThis(mallocSizeOf);
     406             : }
     407             : 
     408             : static size_t
     409           0 : StringLengthWithNullChar(const char* chars)
     410             : {
     411           0 :     return chars ? strlen(chars) + 1 : 0;
     412             : }
     413             : 
     414             : size_t
     415           0 : CacheableChars::serializedSize() const
     416             : {
     417           0 :     return sizeof(uint32_t) + StringLengthWithNullChar(get());
     418             : }
     419             : 
     420             : uint8_t*
     421           0 : CacheableChars::serialize(uint8_t* cursor) const
     422             : {
     423           0 :     uint32_t lengthWithNullChar = StringLengthWithNullChar(get());
     424           0 :     cursor = WriteScalar<uint32_t>(cursor, lengthWithNullChar);
     425           0 :     cursor = WriteBytes(cursor, get(), lengthWithNullChar);
     426           0 :     return cursor;
     427             : }
     428             : 
     429             : const uint8_t*
     430           0 : CacheableChars::deserialize(const uint8_t* cursor)
     431             : {
     432             :     uint32_t lengthWithNullChar;
     433           0 :     cursor = ReadBytes(cursor, &lengthWithNullChar, sizeof(uint32_t));
     434             : 
     435           0 :     if (lengthWithNullChar) {
     436           0 :         reset(js_pod_malloc<char>(lengthWithNullChar));
     437           0 :         if (!get())
     438           0 :             return nullptr;
     439             : 
     440           0 :         cursor = ReadBytes(cursor, get(), lengthWithNullChar);
     441             :     } else {
     442           0 :         MOZ_ASSERT(!get());
     443             :     }
     444             : 
     445           0 :     return cursor;
     446             : }
     447             : 
     448             : size_t
     449           0 : CacheableChars::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
     450             : {
     451           0 :     return mallocSizeOf(get());
     452             : }
     453             : 
     454             : size_t
     455           0 : MetadataTier::serializedSize() const
     456             : {
     457           0 :     return SerializedPodVectorSize(memoryAccesses) +
     458           0 :            SerializedPodVectorSize(codeRanges) +
     459           0 :            SerializedPodVectorSize(callSites) +
     460           0 :            SerializedVectorSize(funcImports) +
     461           0 :            SerializedVectorSize(funcExports);
     462             : }
     463             : 
     464             : size_t
     465           0 : MetadataTier::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
     466             : {
     467           0 :     return memoryAccesses.sizeOfExcludingThis(mallocSizeOf) +
     468           0 :            codeRanges.sizeOfExcludingThis(mallocSizeOf) +
     469           0 :            callSites.sizeOfExcludingThis(mallocSizeOf) +
     470           0 :            SizeOfVectorExcludingThis(funcImports, mallocSizeOf) +
     471           0 :            SizeOfVectorExcludingThis(funcExports, mallocSizeOf);
     472             : }
     473             : 
     474             : uint8_t*
     475           0 : MetadataTier::serialize(uint8_t* cursor) const
     476             : {
     477           0 :     MOZ_ASSERT(debugTrapFarJumpOffsets.empty() && debugFuncToCodeRange.empty());
     478           0 :     cursor = SerializePodVector(cursor, memoryAccesses);
     479           0 :     cursor = SerializePodVector(cursor, codeRanges);
     480           0 :     cursor = SerializePodVector(cursor, callSites);
     481           0 :     cursor = SerializeVector(cursor, funcImports);
     482           0 :     cursor = SerializeVector(cursor, funcExports);
     483           0 :     return cursor;
     484             : }
     485             : 
     486             : /* static */ const uint8_t*
     487           0 : MetadataTier::deserialize(const uint8_t* cursor)
     488             : {
     489           0 :     (cursor = DeserializePodVector(cursor, &memoryAccesses)) &&
     490           0 :     (cursor = DeserializePodVector(cursor, &codeRanges)) &&
     491           0 :     (cursor = DeserializePodVector(cursor, &callSites)) &&
     492           0 :     (cursor = DeserializeVector(cursor, &funcImports)) &&
     493           0 :     (cursor = DeserializeVector(cursor, &funcExports));
     494           0 :     debugTrapFarJumpOffsets.clear();
     495           0 :     debugFuncToCodeRange.clear();
     496           0 :     return cursor;
     497             : }
     498             : 
     499             : Tiers
     500           0 : Metadata::tiers() const
     501             : {
     502           0 :     return Tiers(tier_->tier);
     503             : }
     504             : 
     505             : const MetadataTier&
     506           0 : Metadata::metadata(Tier t) const
     507             : {
     508           0 :     switch (t) {
     509             :       case Tier::Debug:
     510             :       case Tier::Baseline:
     511           0 :         MOZ_RELEASE_ASSERT(tier_->tier == Tier::Baseline);
     512           0 :         return *tier_;
     513             :       case Tier::Ion:
     514           0 :         MOZ_RELEASE_ASSERT(tier_->tier == Tier::Ion);
     515           0 :         return *tier_;
     516             :       case Tier::TBD:
     517           0 :         return *tier_;
     518             :       default:
     519           0 :         MOZ_CRASH();
     520             :     }
     521             : }
     522             : 
     523             : MetadataTier&
     524           0 : Metadata::metadata(Tier t)
     525             : {
     526           0 :     switch (t) {
     527             :       case Tier::Debug:
     528             :       case Tier::Baseline:
     529           0 :         MOZ_RELEASE_ASSERT(tier_->tier == Tier::Baseline);
     530           0 :         return *tier_;
     531             :       case Tier::Ion:
     532           0 :         MOZ_RELEASE_ASSERT(tier_->tier == Tier::Ion);
     533           0 :         return *tier_;
     534             :       case Tier::TBD:
     535           0 :         return *tier_;
     536             :       default:
     537           0 :         MOZ_CRASH();
     538             :     }
     539             : }
     540             : 
     541             : size_t
     542           0 : Metadata::serializedSize() const
     543             : {
     544             :     return sizeof(pod()) +
     545           0 :            metadata(Tier::Ion).serializedSize() +
     546           0 :            SerializedVectorSize(sigIds) +
     547           0 :            SerializedPodVectorSize(globals) +
     548           0 :            SerializedPodVectorSize(tables) +
     549           0 :            SerializedPodVectorSize(funcNames) +
     550           0 :            SerializedPodVectorSize(customSections) +
     551           0 :            filename.serializedSize() +
     552           0 :            sizeof(hash);
     553             : }
     554             : 
     555             : size_t
     556           0 : Metadata::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
     557             : {
     558           0 :     size_t sum = 0;
     559             : 
     560           0 :     for (auto t : tiers())
     561           0 :         sum += metadata(t).sizeOfExcludingThis(mallocSizeOf);
     562             : 
     563           0 :     return sum +
     564           0 :            SizeOfVectorExcludingThis(sigIds, mallocSizeOf) +
     565           0 :            globals.sizeOfExcludingThis(mallocSizeOf) +
     566           0 :            tables.sizeOfExcludingThis(mallocSizeOf) +
     567           0 :            funcNames.sizeOfExcludingThis(mallocSizeOf) +
     568           0 :            customSections.sizeOfExcludingThis(mallocSizeOf) +
     569           0 :            filename.sizeOfExcludingThis(mallocSizeOf);
     570             : }
     571             : 
     572             : uint8_t*
     573           0 : Metadata::serialize(uint8_t* cursor) const
     574             : {
     575           0 :     MOZ_ASSERT(!debugEnabled && debugFuncArgTypes.empty() && debugFuncReturnTypes.empty());
     576           0 :     cursor = WriteBytes(cursor, &pod(), sizeof(pod()));
     577           0 :     cursor = metadata(Tier::Ion).serialize(cursor);
     578           0 :     cursor = SerializeVector(cursor, sigIds);
     579           0 :     cursor = SerializePodVector(cursor, globals);
     580           0 :     cursor = SerializePodVector(cursor, tables);
     581           0 :     cursor = SerializePodVector(cursor, funcNames);
     582           0 :     cursor = SerializePodVector(cursor, customSections);
     583           0 :     cursor = filename.serialize(cursor);
     584           0 :     cursor = WriteBytes(cursor, hash, sizeof(hash));
     585           0 :     return cursor;
     586             : }
     587             : 
     588             : /* static */ const uint8_t*
     589           0 : Metadata::deserialize(const uint8_t* cursor)
     590             : {
     591           0 :     (cursor = ReadBytes(cursor, &pod(), sizeof(pod()))) &&
     592           0 :     (cursor = metadata(Tier::Ion).deserialize(cursor)) &&
     593           0 :     (cursor = DeserializeVector(cursor, &sigIds)) &&
     594           0 :     (cursor = DeserializePodVector(cursor, &globals)) &&
     595           0 :     (cursor = DeserializePodVector(cursor, &tables)) &&
     596           0 :     (cursor = DeserializePodVector(cursor, &funcNames)) &&
     597           0 :     (cursor = DeserializePodVector(cursor, &customSections)) &&
     598           0 :     (cursor = filename.deserialize(cursor)) &&
     599           0 :     (cursor = ReadBytes(cursor, hash, sizeof(hash)));
     600           0 :     debugEnabled = false;
     601           0 :     debugFuncArgTypes.clear();
     602           0 :     debugFuncReturnTypes.clear();
     603           0 :     return cursor;
     604             : }
     605             : 
     606             : struct ProjectFuncIndex
     607             : {
     608             :     const FuncExportVector& funcExports;
     609             : 
     610           0 :     explicit ProjectFuncIndex(const FuncExportVector& funcExports)
     611           0 :       : funcExports(funcExports)
     612           0 :     {}
     613           0 :     uint32_t operator[](size_t index) const {
     614           0 :         return funcExports[index].funcIndex();
     615             :     }
     616             : };
     617             : 
     618             : const FuncExport&
     619           0 : MetadataTier::lookupFuncExport(uint32_t funcIndex) const
     620             : {
     621             :     size_t match;
     622           0 :     if (!BinarySearch(ProjectFuncIndex(funcExports), 0, funcExports.length(), funcIndex, &match))
     623           0 :         MOZ_CRASH("missing function export");
     624             : 
     625           0 :     return funcExports[match];
     626             : }
     627             : 
     628             : bool
     629           0 : Metadata::getFuncName(const Bytes* maybeBytecode, uint32_t funcIndex, UTF8Bytes* name) const
     630             : {
     631           0 :     if (funcIndex < funcNames.length()) {
     632           0 :         MOZ_ASSERT(maybeBytecode, "NameInBytecode requires preserved bytecode");
     633             : 
     634           0 :         const NameInBytecode& n = funcNames[funcIndex];
     635           0 :         MOZ_ASSERT(n.offset + n.length < maybeBytecode->length());
     636             : 
     637           0 :         if (n.length != 0)
     638           0 :             return name->append((const char*)maybeBytecode->begin() + n.offset, n.length);
     639             :     }
     640             : 
     641             :     // For names that are out of range or invalid, synthesize a name.
     642             : 
     643           0 :     const char beforeFuncIndex[] = "wasm-function[";
     644           0 :     const char afterFuncIndex[] = "]";
     645             : 
     646           0 :     ToCStringBuf cbuf;
     647           0 :     const char* funcIndexStr = NumberToCString(nullptr, &cbuf, funcIndex);
     648           0 :     MOZ_ASSERT(funcIndexStr);
     649             : 
     650           0 :     return name->append(beforeFuncIndex, strlen(beforeFuncIndex)) &&
     651           0 :            name->append(funcIndexStr, strlen(funcIndexStr)) &&
     652           0 :            name->append(afterFuncIndex, strlen(afterFuncIndex));
     653             : }
     654             : 
     655           0 : Code::Code(UniqueConstCodeSegment tier, const Metadata& metadata)
     656           0 :   : tier_(Move(tier)),
     657             :     metadata_(&metadata),
     658           0 :     profilingLabels_(mutexid::WasmCodeProfilingLabels, CacheableCharsVector())
     659             : {
     660           0 : }
     661             : 
     662           0 : Code::Code()
     663           0 :   : profilingLabels_(mutexid::WasmCodeProfilingLabels, CacheableCharsVector())
     664             : {
     665           0 : }
     666             : 
     667             : Tier
     668           0 : Code::anyTier() const
     669             : {
     670           0 :     return tier_->tier();
     671             : }
     672             : 
     673             : Tiers
     674           0 : Code::tiers() const
     675             : {
     676           0 :     return Tiers(tier_->tier());
     677             : }
     678             : 
     679             : const CodeSegment&
     680           0 : Code::segment(Tier tier) const
     681             : {
     682           0 :     switch (tier) {
     683             :       case Tier::Debug:
     684             :       case Tier::Baseline:
     685           0 :         MOZ_RELEASE_ASSERT(tier_->tier() == Tier::Baseline);
     686           0 :         return *tier_;
     687             :       case Tier::Ion:
     688           0 :         MOZ_RELEASE_ASSERT(tier_->tier() == Tier::Ion);
     689           0 :         return *tier_;
     690             :       case Tier::TBD:
     691           0 :         return *tier_;
     692             :       default:
     693           0 :         MOZ_CRASH();
     694             :     }
     695             : }
     696             : 
     697             : bool
     698           0 : Code::containsFunctionPC(const void* pc, const CodeSegment** segmentp) const
     699             : {
     700           0 :     for (auto t : tiers()) {
     701           0 :         const CodeSegment& cs = segment(t);
     702           0 :         if (cs.containsFunctionPC(pc)) {
     703           0 :             if (segmentp)
     704           0 :                 *segmentp = &cs;
     705           0 :             return true;
     706             :         }
     707             :     }
     708           0 :     return false;
     709             : }
     710             : 
     711             : bool
     712           0 : Code::containsCodePC(const void* pc, const CodeSegment** segmentp) const
     713             : {
     714           0 :     for (auto t : tiers()) {
     715           0 :         const CodeSegment& cs = segment(t);
     716           0 :         if (cs.containsCodePC(pc)) {
     717           0 :             if (segmentp)
     718           0 :                 *segmentp = &cs;
     719           0 :             return true;
     720             :         }
     721             :     }
     722           0 :     return false;
     723             : }
     724             : 
     725             : struct CallSiteRetAddrOffset
     726             : {
     727             :     const CallSiteVector& callSites;
     728           0 :     explicit CallSiteRetAddrOffset(const CallSiteVector& callSites) : callSites(callSites) {}
     729           0 :     uint32_t operator[](size_t index) const {
     730           0 :         return callSites[index].returnAddressOffset();
     731             :     }
     732             : };
     733             : 
     734             : size_t
     735           0 : Code::serializedSize() const
     736             : {
     737           0 :     return metadata().serializedSize() +
     738           0 :            segment(Tier::Ion).serializedSize();
     739             : }
     740             : 
     741             : uint8_t*
     742           0 : Code::serialize(uint8_t* cursor, const LinkData& linkData) const
     743             : {
     744           0 :     MOZ_RELEASE_ASSERT(!metadata().debugEnabled);
     745             : 
     746           0 :     cursor = metadata().serialize(cursor);
     747           0 :     cursor = segment(Tier::Ion).serialize(cursor, linkData.linkData(Tier::Ion));
     748           0 :     return cursor;
     749             : }
     750             : 
     751             : const uint8_t*
     752           0 : Code::deserialize(const uint8_t* cursor, const SharedBytes& bytecode, const LinkData& linkData,
     753             :                   Metadata* maybeMetadata)
     754             : {
     755           0 :     MutableMetadata metadata;
     756           0 :     if (maybeMetadata) {
     757           0 :         metadata = maybeMetadata;
     758             :     } else {
     759           0 :         auto tier = js::MakeUnique<MetadataTier>(Tier::Ion);
     760           0 :         if (!tier)
     761           0 :             return nullptr;
     762             : 
     763           0 :         metadata = js_new<Metadata>(Move(tier));
     764           0 :         if (!metadata)
     765           0 :             return nullptr;
     766             :     }
     767             : 
     768           0 :     cursor = metadata->deserialize(cursor);
     769           0 :     if (!cursor)
     770           0 :         return nullptr;
     771             : 
     772           0 :     UniqueCodeSegment codeSegment = js::MakeUnique<CodeSegment>();
     773           0 :     if (!codeSegment)
     774           0 :         return nullptr;
     775             : 
     776           0 :     cursor = codeSegment->deserialize(cursor, *bytecode, linkData.linkData(Tier::Ion), *metadata);
     777           0 :     if (!cursor)
     778           0 :         return nullptr;
     779             : 
     780           0 :     tier_ = UniqueConstCodeSegment(codeSegment.release());
     781           0 :     metadata_ = metadata;
     782             : 
     783           0 :     return cursor;
     784             : }
     785             : 
     786             : const CallSite*
     787           0 : Code::lookupCallSite(void* returnAddress, const CodeSegment** segmentp) const
     788             : {
     789           0 :     for (auto t : tiers()) {
     790           0 :         uint32_t target = ((uint8_t*)returnAddress) - segment(t).base();
     791           0 :         size_t lowerBound = 0;
     792           0 :         size_t upperBound = metadata(t).callSites.length();
     793             : 
     794             :         size_t match;
     795           0 :         if (BinarySearch(CallSiteRetAddrOffset(metadata(t).callSites), lowerBound, upperBound,
     796             :                          target, &match))
     797             :         {
     798           0 :             if (segmentp)
     799           0 :                 *segmentp = &segment(t);
     800           0 :             return &metadata(t).callSites[match];
     801             :         }
     802             :     }
     803             : 
     804           0 :     return nullptr;
     805             : }
     806             : 
     807             : const CodeRange*
     808           0 : Code::lookupRange(void* pc, const CodeSegment** segmentp) const
     809             : {
     810           0 :     for (auto t : tiers()) {
     811           0 :         CodeRange::OffsetInCode target((uint8_t*)pc - segment(t).base());
     812           0 :         const CodeRange* result = LookupInSorted(metadata(t).codeRanges, target);
     813           0 :         if (result) {
     814           0 :             if (segmentp)
     815           0 :                 *segmentp = &segment(t);
     816           0 :             return result;
     817             :         }
     818             :     }
     819             : 
     820           0 :     return nullptr;
     821             : }
     822             : 
     823             : struct MemoryAccessOffset
     824             : {
     825             :     const MemoryAccessVector& accesses;
     826           0 :     explicit MemoryAccessOffset(const MemoryAccessVector& accesses) : accesses(accesses) {}
     827           0 :     uintptr_t operator[](size_t index) const {
     828           0 :         return accesses[index].insnOffset();
     829             :     }
     830             : };
     831             : 
     832             : const MemoryAccess*
     833           0 : Code::lookupMemoryAccess(void* pc, const CodeSegment** segmentp) const
     834             : {
     835           0 :     for (auto t : tiers()) {
     836           0 :         MOZ_ASSERT(segment(t).containsFunctionPC(pc));
     837             : 
     838           0 :         const MemoryAccessVector& memoryAccesses = metadata(t).memoryAccesses;
     839             : 
     840           0 :         uint32_t target = ((uint8_t*)pc) - segment(t).base();
     841           0 :         size_t lowerBound = 0;
     842           0 :         size_t upperBound = memoryAccesses.length();
     843             : 
     844             :         size_t match;
     845           0 :         if (BinarySearch(MemoryAccessOffset(memoryAccesses), lowerBound, upperBound, target,
     846             :                          &match))
     847             :         {
     848           0 :             if (segmentp)
     849           0 :                 *segmentp = &segment(t);
     850           0 :             return &memoryAccesses[match];
     851             :         }
     852             :     }
     853           0 :     return nullptr;
     854             : }
     855             : 
     856             : // When enabled, generate profiling labels for every name in funcNames_ that is
     857             : // the name of some Function CodeRange. This involves malloc() so do it now
     858             : // since, once we start sampling, we'll be in a signal-handing context where we
     859             : // cannot malloc.
     860             : void
     861           0 : Code::ensureProfilingLabels(const Bytes* maybeBytecode, bool profilingEnabled) const
     862             : {
     863           0 :     auto labels = profilingLabels_.lock();
     864             : 
     865           0 :     if (!profilingEnabled) {
     866           0 :         labels->clear();
     867           0 :         return;
     868             :     }
     869             : 
     870           0 :     if (!labels->empty())
     871           0 :         return;
     872             : 
     873             :     // Any tier will do, we only need tier-invariant data that are incidentally
     874             :     // stored with the code ranges.
     875             : 
     876           0 :     for (const CodeRange& codeRange : metadata(anyTier()).codeRanges) {
     877           0 :         if (!codeRange.isFunction())
     878           0 :             continue;
     879             : 
     880           0 :         ToCStringBuf cbuf;
     881           0 :         const char* bytecodeStr = NumberToCString(nullptr, &cbuf, codeRange.funcLineOrBytecode());
     882           0 :         MOZ_ASSERT(bytecodeStr);
     883             : 
     884           0 :         UTF8Bytes name;
     885           0 :         if (!metadata().getFuncName(maybeBytecode, codeRange.funcIndex(), &name))
     886           0 :             return;
     887           0 :         if (!name.append(" (", 2))
     888           0 :             return;
     889             : 
     890           0 :         if (const char* filename = metadata().filename.get()) {
     891           0 :             if (!name.append(filename, strlen(filename)))
     892           0 :                 return;
     893             :         } else {
     894           0 :             if (!name.append('?'))
     895           0 :                 return;
     896             :         }
     897             : 
     898           0 :         if (!name.append(':') ||
     899           0 :             !name.append(bytecodeStr, strlen(bytecodeStr)) ||
     900           0 :             !name.append(")\0", 2))
     901             :         {
     902           0 :             return;
     903             :         }
     904             : 
     905           0 :         UniqueChars label(name.extractOrCopyRawBuffer());
     906           0 :         if (!label)
     907           0 :             return;
     908             : 
     909           0 :         if (codeRange.funcIndex() >= labels->length()) {
     910           0 :             if (!labels->resize(codeRange.funcIndex() + 1))
     911           0 :                 return;
     912             :         }
     913             : 
     914           0 :         ((CacheableCharsVector&)labels)[codeRange.funcIndex()] = Move(label);
     915             :     }
     916             : }
     917             : 
     918             : const char*
     919           0 : Code::profilingLabel(uint32_t funcIndex) const
     920             : {
     921           0 :     auto labels = profilingLabels_.lock();
     922             : 
     923           0 :     if (funcIndex >= labels->length() || !((CacheableCharsVector&)labels)[funcIndex])
     924           0 :         return "?";
     925           0 :     return ((CacheableCharsVector&)labels)[funcIndex].get();
     926             : }
     927             : 
     928             : void
     929           0 : Code::addSizeOfMiscIfNotSeen(MallocSizeOf mallocSizeOf,
     930             :                              Metadata::SeenSet* seenMetadata,
     931             :                              Code::SeenSet* seenCode,
     932             :                              size_t* code,
     933             :                              size_t* data) const
     934             : {
     935           0 :     auto p = seenCode->lookupForAdd(this);
     936           0 :     if (p)
     937           0 :         return;
     938           0 :     bool ok = seenCode->add(p, this);
     939             :     (void)ok;  // oh well
     940             : 
     941           0 :     *data += mallocSizeOf(this) +
     942           0 :              metadata().sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenMetadata) +
     943           0 :              profilingLabels_.lock()->sizeOfExcludingThis(mallocSizeOf);
     944             : 
     945           0 :     for (auto t : tiers())
     946           0 :         segment(t).addSizeOfMisc(mallocSizeOf, code, data);
     947             : }

Generated by: LCOV version 1.13