LCOV - code coverage report
Current view: top level - js/src/wasm - WasmModule.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 544 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 42 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 2015 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/WasmModule.h"
      20             : 
      21             : #include "jsnspr.h"
      22             : 
      23             : #include "jit/JitOptions.h"
      24             : #include "wasm/WasmCompile.h"
      25             : #include "wasm/WasmInstance.h"
      26             : #include "wasm/WasmJS.h"
      27             : #include "wasm/WasmSerialize.h"
      28             : 
      29             : #include "jsatominlines.h"
      30             : 
      31             : #include "vm/ArrayBufferObject-inl.h"
      32             : #include "vm/Debugger-inl.h"
      33             : 
      34             : using namespace js;
      35             : using namespace js::jit;
      36             : using namespace js::wasm;
      37             : 
      38             : using mozilla::IsNaN;
      39             : 
      40             : #if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
      41             : // On MIPS, CodeLabels are instruction immediates so InternalLinks only
      42             : // patch instruction immediates.
      43             : LinkDataTier::InternalLink::InternalLink(Kind kind)
      44             : {
      45             :     MOZ_ASSERT(kind == CodeLabel || kind == InstructionImmediate);
      46             : }
      47             : 
      48             : bool
      49             : LinkDataTier::InternalLink::isRawPointerPatch()
      50             : {
      51             :     return false;
      52             : }
      53             : #else
      54             : // On the rest, CodeLabels are raw pointers so InternalLinks only patch
      55             : // raw pointers.
      56           0 : LinkDataTier::InternalLink::InternalLink(Kind kind)
      57             : {
      58           0 :     MOZ_ASSERT(kind == CodeLabel || kind == RawPointer);
      59           0 : }
      60             : 
      61             : bool
      62           0 : LinkDataTier::InternalLink::isRawPointerPatch()
      63             : {
      64           0 :     return true;
      65             : }
      66             : #endif
      67             : 
      68             : size_t
      69           0 : LinkDataTier::SymbolicLinkArray::serializedSize() const
      70             : {
      71           0 :     size_t size = 0;
      72           0 :     for (const Uint32Vector& offsets : *this)
      73           0 :         size += SerializedPodVectorSize(offsets);
      74           0 :     return size;
      75             : }
      76             : 
      77             : uint8_t*
      78           0 : LinkDataTier::SymbolicLinkArray::serialize(uint8_t* cursor) const
      79             : {
      80           0 :     for (const Uint32Vector& offsets : *this)
      81           0 :         cursor = SerializePodVector(cursor, offsets);
      82           0 :     return cursor;
      83             : }
      84             : 
      85             : const uint8_t*
      86           0 : LinkDataTier::SymbolicLinkArray::deserialize(const uint8_t* cursor)
      87             : {
      88           0 :     for (Uint32Vector& offsets : *this) {
      89           0 :         cursor = DeserializePodVector(cursor, &offsets);
      90           0 :         if (!cursor)
      91           0 :             return nullptr;
      92             :     }
      93           0 :     return cursor;
      94             : }
      95             : 
      96             : size_t
      97           0 : LinkDataTier::SymbolicLinkArray::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
      98             : {
      99           0 :     size_t size = 0;
     100           0 :     for (const Uint32Vector& offsets : *this)
     101           0 :         size += offsets.sizeOfExcludingThis(mallocSizeOf);
     102           0 :     return size;
     103             : }
     104             : 
     105             : size_t
     106           0 : LinkDataTier::serializedSize() const
     107             : {
     108             :     return sizeof(pod()) +
     109           0 :            SerializedPodVectorSize(internalLinks) +
     110           0 :            symbolicLinks.serializedSize();
     111             : }
     112             : 
     113             : uint8_t*
     114           0 : LinkDataTier::serialize(uint8_t* cursor) const
     115             : {
     116           0 :     MOZ_ASSERT(tier == Tier::Ion);
     117             : 
     118           0 :     cursor = WriteBytes(cursor, &pod(), sizeof(pod()));
     119           0 :     cursor = SerializePodVector(cursor, internalLinks);
     120           0 :     cursor = symbolicLinks.serialize(cursor);
     121           0 :     return cursor;
     122             : }
     123             : 
     124             : const uint8_t*
     125           0 : LinkDataTier::deserialize(const uint8_t* cursor)
     126             : {
     127           0 :     (cursor = ReadBytes(cursor, &pod(), sizeof(pod()))) &&
     128           0 :     (cursor = DeserializePodVector(cursor, &internalLinks)) &&
     129           0 :     (cursor = symbolicLinks.deserialize(cursor));
     130           0 :     return cursor;
     131             : }
     132             : 
     133             : size_t
     134           0 : LinkDataTier::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
     135             : {
     136           0 :     return internalLinks.sizeOfExcludingThis(mallocSizeOf) +
     137           0 :            symbolicLinks.sizeOfExcludingThis(mallocSizeOf);
     138             : }
     139             : 
     140             : Tiers
     141           0 : LinkData::tiers() const
     142             : {
     143           0 :     return Tiers(tier_->tier);
     144             : }
     145             : 
     146             : const LinkDataTier&
     147           0 : LinkData::linkData(Tier tier) const
     148             : {
     149           0 :     switch (tier) {
     150             :       case Tier::Debug:
     151             :       case Tier::Baseline:
     152           0 :         MOZ_RELEASE_ASSERT(tier_->tier == Tier::Baseline);
     153           0 :         return *tier_;
     154             :       case Tier::Ion:
     155           0 :         MOZ_RELEASE_ASSERT(tier_->tier == Tier::Ion);
     156           0 :         return *tier_;
     157             :       case Tier::TBD:
     158           0 :         return *tier_;
     159             :       default:
     160           0 :         MOZ_CRASH();
     161             :     }
     162             : }
     163             : 
     164             : LinkDataTier&
     165           0 : LinkData::linkData(Tier tier)
     166             : {
     167           0 :     switch (tier) {
     168             :       case Tier::Debug:
     169             :       case Tier::Baseline:
     170           0 :         MOZ_RELEASE_ASSERT(tier_->tier == Tier::Baseline);
     171           0 :         return *tier_;
     172             :       case Tier::Ion:
     173           0 :         MOZ_RELEASE_ASSERT(tier_->tier == Tier::Ion);
     174           0 :         return *tier_;
     175             :       case Tier::TBD:
     176           0 :         return *tier_;
     177             :       default:
     178           0 :         MOZ_CRASH();
     179             :     }
     180             : }
     181             : 
     182             : bool
     183           0 : LinkData::initTier(Tier tier)
     184             : {
     185           0 :     MOZ_ASSERT(!tier_);
     186           0 :     tier_ = js::MakeUnique<LinkDataTier>(tier);
     187           0 :     return tier_ != nullptr;
     188             : }
     189             : 
     190             : size_t
     191           0 : LinkData::serializedSize() const
     192             : {
     193           0 :     return tier_->serializedSize();
     194             : }
     195             : 
     196             : uint8_t*
     197           0 : LinkData::serialize(uint8_t* cursor) const
     198             : {
     199           0 :     cursor = tier_->serialize(cursor);
     200           0 :     return cursor;
     201             : }
     202             : 
     203             : const uint8_t*
     204           0 : LinkData::deserialize(const uint8_t* cursor)
     205             : {
     206           0 :     (cursor = tier_->deserialize(cursor));
     207           0 :     return cursor;
     208             : }
     209             : 
     210             : size_t
     211           0 : LinkData::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
     212             : {
     213           0 :     return tier_->sizeOfExcludingThis(mallocSizeOf);
     214             : }
     215             : 
     216             : /* virtual */ void
     217           0 : Module::serializedSize(size_t* maybeBytecodeSize, size_t* maybeCompiledSize) const
     218             : {
     219           0 :     if (maybeBytecodeSize)
     220           0 :         *maybeBytecodeSize = bytecode_->bytes.length();
     221             : 
     222             :     // The compiled debug code must not be saved, set compiled size to 0,
     223             :     // so Module::assumptionsMatch will return false during assumptions
     224             :     // deserialization.
     225           0 :     if (maybeCompiledSize && metadata().debugEnabled)
     226           0 :         *maybeCompiledSize = 0;
     227             : 
     228           0 :     if (maybeCompiledSize && !metadata().debugEnabled) {
     229           0 :         *maybeCompiledSize = assumptions_.serializedSize() +
     230           0 :                              linkData_.serializedSize() +
     231           0 :                              SerializedVectorSize(imports_) +
     232           0 :                              SerializedVectorSize(exports_) +
     233           0 :                              SerializedPodVectorSize(dataSegments_) +
     234           0 :                              SerializedVectorSize(elemSegments_) +
     235           0 :                              code_->serializedSize();
     236             :     }
     237           0 : }
     238             : 
     239             : /* virtual */ void
     240           0 : Module::serialize(uint8_t* maybeBytecodeBegin, size_t maybeBytecodeSize,
     241             :                   uint8_t* maybeCompiledBegin, size_t maybeCompiledSize) const
     242             : {
     243           0 :     MOZ_ASSERT(!!maybeBytecodeBegin == !!maybeBytecodeSize);
     244           0 :     MOZ_ASSERT(!!maybeCompiledBegin == !!maybeCompiledSize);
     245             : 
     246           0 :     if (maybeBytecodeBegin) {
     247             :         // Bytecode deserialization is not guarded by Assumptions and thus must not
     248             :         // change incompatibly between builds. Thus, for simplicity, the format
     249             :         // of the bytecode file is simply a .wasm file (thus, backwards
     250             :         // compatibility is ensured by backwards compatibility of the wasm
     251             :         // binary format).
     252             : 
     253           0 :         const Bytes& bytes = bytecode_->bytes;
     254           0 :         uint8_t* bytecodeEnd = WriteBytes(maybeBytecodeBegin, bytes.begin(), bytes.length());
     255           0 :         MOZ_RELEASE_ASSERT(bytecodeEnd == maybeBytecodeBegin + maybeBytecodeSize);
     256             :     }
     257             : 
     258           0 :     MOZ_ASSERT_IF(maybeCompiledBegin && metadata().debugEnabled, maybeCompiledSize == 0);
     259             : 
     260           0 :     if (maybeCompiledBegin && !metadata().debugEnabled) {
     261             :         // Assumption must be serialized at the beginning of the compiled bytes so
     262             :         // that compiledAssumptionsMatch can detect a build-id mismatch before any
     263             :         // other decoding occurs.
     264             : 
     265           0 :         uint8_t* cursor = maybeCompiledBegin;
     266           0 :         cursor = assumptions_.serialize(cursor);
     267           0 :         cursor = linkData_.serialize(cursor);
     268           0 :         cursor = SerializeVector(cursor, imports_);
     269           0 :         cursor = SerializeVector(cursor, exports_);
     270           0 :         cursor = SerializePodVector(cursor, dataSegments_);
     271           0 :         cursor = SerializeVector(cursor, elemSegments_);
     272           0 :         cursor = code_->serialize(cursor, linkData_);
     273           0 :         MOZ_RELEASE_ASSERT(cursor == maybeCompiledBegin + maybeCompiledSize);
     274             :     }
     275           0 : }
     276             : 
     277             : /* static */ bool
     278           0 : Module::assumptionsMatch(const Assumptions& current, const uint8_t* compiledBegin, size_t remain)
     279             : {
     280           0 :     Assumptions cached;
     281           0 :     if (!cached.deserialize(compiledBegin, remain))
     282           0 :         return false;
     283             : 
     284           0 :     return current == cached;
     285             : }
     286             : 
     287             : /* static */ SharedModule
     288           0 : Module::deserialize(const uint8_t* bytecodeBegin, size_t bytecodeSize,
     289             :                     const uint8_t* compiledBegin, size_t compiledSize,
     290             :                     Metadata* maybeMetadata)
     291             : {
     292           0 :     MutableBytes bytecode = js_new<ShareableBytes>();
     293           0 :     if (!bytecode || !bytecode->bytes.initLengthUninitialized(bytecodeSize))
     294           0 :         return nullptr;
     295             : 
     296           0 :     memcpy(bytecode->bytes.begin(), bytecodeBegin, bytecodeSize);
     297             : 
     298           0 :     Assumptions assumptions;
     299           0 :     const uint8_t* cursor = assumptions.deserialize(compiledBegin, compiledSize);
     300           0 :     if (!cursor)
     301           0 :         return nullptr;
     302             : 
     303           0 :     LinkData linkData;
     304           0 :     if (!linkData.initTier(Tier::Ion))
     305           0 :         return nullptr;
     306             : 
     307           0 :     cursor = linkData.deserialize(cursor);
     308           0 :     if (!cursor)
     309           0 :         return nullptr;
     310             : 
     311           0 :     ImportVector imports;
     312           0 :     cursor = DeserializeVector(cursor, &imports);
     313           0 :     if (!cursor)
     314           0 :         return nullptr;
     315             : 
     316           0 :     ExportVector exports;
     317           0 :     cursor = DeserializeVector(cursor, &exports);
     318           0 :     if (!cursor)
     319           0 :         return nullptr;
     320             : 
     321           0 :     DataSegmentVector dataSegments;
     322           0 :     cursor = DeserializePodVector(cursor, &dataSegments);
     323           0 :     if (!cursor)
     324           0 :         return nullptr;
     325             : 
     326           0 :     ElemSegmentVector elemSegments;
     327           0 :     cursor = DeserializeVector(cursor, &elemSegments);
     328           0 :     if (!cursor)
     329           0 :         return nullptr;
     330             : 
     331           0 :     MutableCode code = js_new<Code>();
     332           0 :     cursor = code->deserialize(cursor, bytecode, linkData, maybeMetadata);
     333           0 :     if (!cursor)
     334           0 :         return nullptr;
     335             : 
     336           0 :     MOZ_RELEASE_ASSERT(cursor == compiledBegin + compiledSize);
     337           0 :     MOZ_RELEASE_ASSERT(!!maybeMetadata == code->metadata().isAsmJS());
     338             : 
     339           0 :     return js_new<Module>(Move(assumptions),
     340             :                           *code,
     341             :                           nullptr, // Serialized code is never debuggable
     342           0 :                           Move(linkData),
     343           0 :                           Move(imports),
     344           0 :                           Move(exports),
     345           0 :                           Move(dataSegments),
     346           0 :                           Move(elemSegments),
     347           0 :                           *bytecode);
     348             : }
     349             : 
     350             : /* virtual */ JSObject*
     351           0 : Module::createObject(JSContext* cx)
     352             : {
     353           0 :     if (!GlobalObject::ensureConstructor(cx, cx->global(), JSProto_WebAssembly))
     354           0 :         return nullptr;
     355             : 
     356           0 :     RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmModule).toObject());
     357           0 :     return WasmModuleObject::create(cx, *this, proto);
     358             : }
     359             : 
     360             : struct MemUnmap
     361             : {
     362             :     uint32_t size;
     363           0 :     MemUnmap() : size(0) {}
     364           0 :     explicit MemUnmap(uint32_t size) : size(size) {}
     365           0 :     void operator()(uint8_t* p) { MOZ_ASSERT(size); PR_MemUnmap(p, size); }
     366             : };
     367             : 
     368             : typedef UniquePtr<uint8_t, MemUnmap> UniqueMapping;
     369             : 
     370             : static UniqueMapping
     371           0 : MapFile(PRFileDesc* file, PRFileInfo* info)
     372             : {
     373           0 :     if (PR_GetOpenFileInfo(file, info) != PR_SUCCESS)
     374           0 :         return nullptr;
     375             : 
     376           0 :     PRFileMap* map = PR_CreateFileMap(file, info->size, PR_PROT_READONLY);
     377           0 :     if (!map)
     378           0 :         return nullptr;
     379             : 
     380             :     // PRFileMap objects do not need to be kept alive after the memory has been
     381             :     // mapped, so unconditionally close the PRFileMap, regardless of whether
     382             :     // PR_MemMap succeeds.
     383           0 :     uint8_t* memory = (uint8_t*)PR_MemMap(map, 0, info->size);
     384           0 :     PR_CloseFileMap(map);
     385           0 :     return UniqueMapping(memory, MemUnmap(info->size));
     386             : }
     387             : 
     388             : bool
     389           0 : wasm::CompiledModuleAssumptionsMatch(PRFileDesc* compiled, JS::BuildIdCharVector&& buildId)
     390             : {
     391             :     PRFileInfo info;
     392           0 :     UniqueMapping mapping = MapFile(compiled, &info);
     393           0 :     if (!mapping)
     394           0 :         return false;
     395             : 
     396           0 :     Assumptions assumptions(Move(buildId));
     397           0 :     return Module::assumptionsMatch(assumptions, mapping.get(), info.size);
     398             : }
     399             : 
     400             : SharedModule
     401           0 : wasm::DeserializeModule(PRFileDesc* bytecodeFile, PRFileDesc* maybeCompiledFile,
     402             :                         JS::BuildIdCharVector&& buildId, UniqueChars filename,
     403             :                         unsigned line, unsigned column)
     404             : {
     405             :     PRFileInfo bytecodeInfo;
     406           0 :     UniqueMapping bytecodeMapping = MapFile(bytecodeFile, &bytecodeInfo);
     407           0 :     if (!bytecodeMapping)
     408           0 :         return nullptr;
     409             : 
     410           0 :     if (PRFileDesc* compiledFile = maybeCompiledFile) {
     411             :         PRFileInfo compiledInfo;
     412           0 :         UniqueMapping compiledMapping = MapFile(compiledFile, &compiledInfo);
     413           0 :         if (!compiledMapping)
     414           0 :             return nullptr;
     415             : 
     416           0 :         return Module::deserialize(bytecodeMapping.get(), bytecodeInfo.size,
     417           0 :                                    compiledMapping.get(), compiledInfo.size);
     418             :     }
     419             : 
     420             :     // Since the compiled file's assumptions don't match, we must recompile from
     421             :     // bytecode. The bytecode file format is simply that of a .wasm (see
     422             :     // Module::serialize).
     423             : 
     424           0 :     MutableBytes bytecode = js_new<ShareableBytes>();
     425           0 :     if (!bytecode || !bytecode->bytes.initLengthUninitialized(bytecodeInfo.size))
     426           0 :         return nullptr;
     427             : 
     428           0 :     memcpy(bytecode->bytes.begin(), bytecodeMapping.get(), bytecodeInfo.size);
     429             : 
     430           0 :     ScriptedCaller scriptedCaller;
     431           0 :     scriptedCaller.filename = Move(filename);
     432           0 :     scriptedCaller.line = line;
     433           0 :     scriptedCaller.column = column;
     434             : 
     435           0 :     CompileArgs args(Assumptions(Move(buildId)), Move(scriptedCaller));
     436             : 
     437           0 :     UniqueChars error;
     438           0 :     return Compile(*bytecode, Move(args), &error);
     439             : }
     440             : 
     441             : /* virtual */ void
     442           0 : Module::addSizeOfMisc(MallocSizeOf mallocSizeOf,
     443             :                       Metadata::SeenSet* seenMetadata,
     444             :                       ShareableBytes::SeenSet* seenBytes,
     445             :                       Code::SeenSet* seenCode,
     446             :                       size_t* code,
     447             :                       size_t* data) const
     448             : {
     449           0 :     code_->addSizeOfMiscIfNotSeen(mallocSizeOf, seenMetadata, seenCode, code, data);
     450           0 :     *data += mallocSizeOf(this) +
     451           0 :              assumptions_.sizeOfExcludingThis(mallocSizeOf) +
     452           0 :              linkData_.sizeOfExcludingThis(mallocSizeOf) +
     453           0 :              SizeOfVectorExcludingThis(imports_, mallocSizeOf) +
     454           0 :              SizeOfVectorExcludingThis(exports_, mallocSizeOf) +
     455           0 :              dataSegments_.sizeOfExcludingThis(mallocSizeOf) +
     456           0 :              SizeOfVectorExcludingThis(elemSegments_, mallocSizeOf) +
     457           0 :              bytecode_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenBytes);
     458           0 :     if (unlinkedCodeForDebugging_)
     459           0 :         *data += unlinkedCodeForDebugging_->sizeOfExcludingThis(mallocSizeOf);
     460           0 : }
     461             : 
     462             : 
     463             : // Extracting machine code as JS object. The result has the "code" property, as
     464             : // a Uint8Array, and the "segments" property as array objects. The objects
     465             : // contain offsets in the "code" array and basic information about a code
     466             : // segment/function body.
     467             : bool
     468           0 : Module::extractCode(JSContext* cx, MutableHandleValue vp) const
     469             : {
     470           0 :     RootedPlainObject result(cx, NewBuiltinClassInstance<PlainObject>(cx));
     471           0 :     if (!result)
     472           0 :         return false;
     473             : 
     474             :     // The tier could be a parameter to extractCode. For now, any tier will do.
     475           0 :     Tier tier = code().anyTier();
     476             : 
     477           0 :     const CodeSegment& codeSegment = code_->segment(tier);
     478           0 :     RootedObject code(cx, JS_NewUint8Array(cx, codeSegment.length()));
     479           0 :     if (!code)
     480           0 :         return false;
     481             : 
     482           0 :     memcpy(code->as<TypedArrayObject>().viewDataUnshared(), codeSegment.base(), codeSegment.length());
     483             : 
     484           0 :     RootedValue value(cx, ObjectValue(*code));
     485           0 :     if (!JS_DefineProperty(cx, result, "code", value, JSPROP_ENUMERATE))
     486           0 :         return false;
     487             : 
     488           0 :     RootedObject segments(cx, NewDenseEmptyArray(cx));
     489           0 :     if (!segments)
     490           0 :         return false;
     491             : 
     492           0 :     for (const CodeRange& p : metadata(tier).codeRanges) {
     493           0 :         RootedObject segment(cx, NewObjectWithGivenProto<PlainObject>(cx, nullptr));
     494           0 :         if (!segment)
     495           0 :             return false;
     496             : 
     497           0 :         value.setNumber((uint32_t)p.begin());
     498           0 :         if (!JS_DefineProperty(cx, segment, "begin", value, JSPROP_ENUMERATE))
     499           0 :             return false;
     500             : 
     501           0 :         value.setNumber((uint32_t)p.end());
     502           0 :         if (!JS_DefineProperty(cx, segment, "end", value, JSPROP_ENUMERATE))
     503           0 :             return false;
     504             : 
     505           0 :         value.setNumber((uint32_t)p.kind());
     506           0 :         if (!JS_DefineProperty(cx, segment, "kind", value, JSPROP_ENUMERATE))
     507           0 :             return false;
     508             : 
     509           0 :         if (p.isFunction()) {
     510           0 :             value.setNumber((uint32_t)p.funcIndex());
     511           0 :             if (!JS_DefineProperty(cx, segment, "funcIndex", value, JSPROP_ENUMERATE))
     512           0 :                 return false;
     513             : 
     514           0 :             value.setNumber((uint32_t)p.funcNormalEntry());
     515           0 :             if (!JS_DefineProperty(cx, segment, "funcBodyBegin", value, JSPROP_ENUMERATE))
     516           0 :                 return false;
     517             : 
     518           0 :             value.setNumber((uint32_t)p.end());
     519           0 :             if (!JS_DefineProperty(cx, segment, "funcBodyEnd", value, JSPROP_ENUMERATE))
     520           0 :                 return false;
     521             :         }
     522             : 
     523           0 :         if (!NewbornArrayPush(cx, segments, ObjectValue(*segment)))
     524           0 :             return false;
     525             :     }
     526             : 
     527           0 :     value.setObject(*segments);
     528           0 :     if (!JS_DefineProperty(cx, result, "segments", value, JSPROP_ENUMERATE))
     529           0 :         return false;
     530             : 
     531           0 :     vp.setObject(*result);
     532           0 :     return true;
     533             : }
     534             : 
     535             : static uint32_t
     536           0 : EvaluateInitExpr(const ValVector& globalImports, InitExpr initExpr)
     537             : {
     538           0 :     switch (initExpr.kind()) {
     539             :       case InitExpr::Kind::Constant:
     540           0 :         return initExpr.val().i32();
     541             :       case InitExpr::Kind::GetGlobal:
     542           0 :         return globalImports[initExpr.globalIndex()].i32();
     543             :     }
     544             : 
     545           0 :     MOZ_CRASH("bad initializer expression");
     546             : }
     547             : 
     548             : bool
     549           0 : Module::initSegments(JSContext* cx,
     550             :                      HandleWasmInstanceObject instanceObj,
     551             :                      Handle<FunctionVector> funcImports,
     552             :                      HandleWasmMemoryObject memoryObj,
     553             :                      const ValVector& globalImports) const
     554             : {
     555           0 :     Instance& instance = instanceObj->instance();
     556           0 :     const SharedTableVector& tables = instance.tables();
     557             : 
     558             :     // Perform all error checks up front so that this function does not perform
     559             :     // partial initialization if an error is reported.
     560             : 
     561           0 :     for (const ElemSegment& seg : elemSegments_) {
     562           0 :         uint32_t numElems = seg.elemCodeRangeIndices.length();
     563             : 
     564           0 :         uint32_t tableLength = tables[seg.tableIndex]->length();
     565           0 :         uint32_t offset = EvaluateInitExpr(globalImports, seg.offset);
     566             : 
     567           0 :         if (offset > tableLength || tableLength - offset < numElems) {
     568             :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_FIT,
     569           0 :                                       "elem", "table");
     570           0 :             return false;
     571             :         }
     572             :     }
     573             : 
     574           0 :     if (memoryObj) {
     575           0 :         for (const DataSegment& seg : dataSegments_) {
     576           0 :             uint32_t memoryLength = memoryObj->buffer().byteLength();
     577           0 :             uint32_t offset = EvaluateInitExpr(globalImports, seg.offset);
     578             : 
     579           0 :             if (offset > memoryLength || memoryLength - offset < seg.length) {
     580             :                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_FIT,
     581           0 :                                           "data", "memory");
     582           0 :                 return false;
     583             :             }
     584             :         }
     585             :     } else {
     586           0 :         MOZ_ASSERT(dataSegments_.empty());
     587             :     }
     588             : 
     589             :     // Now that initialization can't fail partway through, write data/elem
     590             :     // segments into memories/tables.
     591             : 
     592           0 :     for (const ElemSegment& seg : elemSegments_) {
     593           0 :         Table& table = *tables[seg.tableIndex];
     594           0 :         uint32_t offset = EvaluateInitExpr(globalImports, seg.offset);
     595           0 :         Tier tier = Tier::TBD;
     596           0 :         const CodeRangeVector& codeRanges = metadata(tier).codeRanges;
     597           0 :         uint8_t* codeBase = instance.codeBase(tier);
     598             : 
     599           0 :         for (uint32_t i = 0; i < seg.elemCodeRangeIndices.length(); i++) {
     600           0 :             uint32_t funcIndex = seg.elemFuncIndices[i];
     601           0 :             if (funcIndex < funcImports.length() && IsExportedWasmFunction(funcImports[funcIndex])) {
     602           0 :                 MOZ_ASSERT(!metadata().isAsmJS());
     603           0 :                 MOZ_ASSERT(!table.isTypedFunction());
     604             : 
     605           0 :                 HandleFunction f = funcImports[funcIndex];
     606           0 :                 WasmInstanceObject* exportInstanceObj = ExportedFunctionToInstanceObject(f);
     607           0 :                 Tier exportTier = Tier::TBD;
     608           0 :                 const CodeRange& cr = exportInstanceObj->getExportedFunctionCodeRange(f, exportTier);
     609           0 :                 Instance& exportInstance = exportInstanceObj->instance();
     610           0 :                 table.set(offset + i, exportInstance.codeBase(exportTier) + cr.funcTableEntry(), exportInstance);
     611             :             } else {
     612           0 :                 const CodeRange& cr = codeRanges[seg.elemCodeRangeIndices[i]];
     613           0 :                 uint32_t entryOffset = table.isTypedFunction()
     614           0 :                                        ? cr.funcNormalEntry()
     615           0 :                                        : cr.funcTableEntry();
     616           0 :                 table.set(offset + i, codeBase + entryOffset, instance);
     617             :             }
     618             :         }
     619             :     }
     620             : 
     621           0 :     if (memoryObj) {
     622           0 :         uint8_t* memoryBase = memoryObj->buffer().dataPointerEither().unwrap(/* memcpy */);
     623             : 
     624           0 :         for (const DataSegment& seg : dataSegments_) {
     625           0 :             MOZ_ASSERT(seg.bytecodeOffset <= bytecode_->length());
     626           0 :             MOZ_ASSERT(seg.length <= bytecode_->length() - seg.bytecodeOffset);
     627           0 :             uint32_t offset = EvaluateInitExpr(globalImports, seg.offset);
     628           0 :             memcpy(memoryBase + offset, bytecode_->begin() + seg.bytecodeOffset, seg.length);
     629             :         }
     630             :     }
     631             : 
     632           0 :     return true;
     633             : }
     634             : 
     635             : static const Import&
     636           0 : FindImportForFuncImport(const ImportVector& imports, uint32_t funcImportIndex)
     637             : {
     638           0 :     for (const Import& import : imports) {
     639           0 :         if (import.kind != DefinitionKind::Function)
     640           0 :             continue;
     641           0 :         if (funcImportIndex == 0)
     642           0 :             return import;
     643           0 :         funcImportIndex--;
     644             :     }
     645           0 :     MOZ_CRASH("ran out of imports");
     646             : }
     647             : 
     648             : bool
     649           0 : Module::instantiateFunctions(JSContext* cx, Handle<FunctionVector> funcImports) const
     650             : {
     651             : #ifdef DEBUG
     652           0 :     for (auto t : code().tiers())
     653           0 :         MOZ_ASSERT(funcImports.length() == metadata(t).funcImports.length());
     654             : #endif
     655             : 
     656           0 :     if (metadata().isAsmJS())
     657           0 :         return true;
     658             : 
     659           0 :     Tier tier = code().anyTier();
     660             : 
     661           0 :     for (size_t i = 0; i < metadata(tier).funcImports.length(); i++) {
     662           0 :         HandleFunction f = funcImports[i];
     663           0 :         if (!IsExportedFunction(f) || ExportedFunctionToInstance(f).isAsmJS())
     664           0 :             continue;
     665             : 
     666           0 :         uint32_t funcIndex = ExportedFunctionToFuncIndex(f);
     667           0 :         Instance& instance = ExportedFunctionToInstance(f);
     668           0 :         const FuncExport& funcExport = instance.metadata(tier).lookupFuncExport(funcIndex);
     669             : 
     670           0 :         if (funcExport.sig() != metadata(tier).funcImports[i].sig()) {
     671           0 :             const Import& import = FindImportForFuncImport(imports_, i);
     672           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMPORT_SIG,
     673           0 :                                       import.module.get(), import.field.get());
     674           0 :             return false;
     675             :         }
     676             :     }
     677             : 
     678           0 :     return true;
     679             : }
     680             : 
     681             : static bool
     682           0 : CheckLimits(JSContext* cx, uint32_t declaredMin, const Maybe<uint32_t>& declaredMax, uint32_t actualLength,
     683             :             const Maybe<uint32_t>& actualMax, bool isAsmJS, const char* kind)
     684             : {
     685           0 :     if (isAsmJS) {
     686           0 :         MOZ_ASSERT(actualLength >= declaredMin);
     687           0 :         MOZ_ASSERT(!declaredMax);
     688           0 :         MOZ_ASSERT(actualLength == actualMax.value());
     689           0 :         return true;
     690             :     }
     691             : 
     692           0 :     if (actualLength < declaredMin || actualLength > declaredMax.valueOr(UINT32_MAX)) {
     693           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMP_SIZE, kind);
     694           0 :         return false;
     695             :     }
     696             : 
     697           0 :     if ((actualMax && declaredMax && *actualMax > *declaredMax) || (!actualMax && declaredMax)) {
     698           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_IMP_MAX, kind);
     699           0 :         return false;
     700             :     }
     701             : 
     702           0 :     return true;
     703             : }
     704             : 
     705             : // asm.js module instantiation supplies its own buffer, but for wasm, create and
     706             : // initialize the buffer if one is requested. Either way, the buffer is wrapped
     707             : // in a WebAssembly.Memory object which is what the Instance stores.
     708             : bool
     709           0 : Module::instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) const
     710             : {
     711           0 :     if (!metadata().usesMemory()) {
     712           0 :         MOZ_ASSERT(!memory);
     713           0 :         MOZ_ASSERT(dataSegments_.empty());
     714           0 :         return true;
     715             :     }
     716             : 
     717           0 :     uint32_t declaredMin = metadata().minMemoryLength;
     718           0 :     Maybe<uint32_t> declaredMax = metadata().maxMemoryLength;
     719             : 
     720           0 :     if (memory) {
     721           0 :         ArrayBufferObjectMaybeShared& buffer = memory->buffer();
     722           0 :         MOZ_ASSERT_IF(metadata().isAsmJS(), buffer.isPreparedForAsmJS());
     723           0 :         MOZ_ASSERT_IF(!metadata().isAsmJS(), buffer.as<ArrayBufferObject>().isWasm());
     724             : 
     725           0 :         if (!CheckLimits(cx, declaredMin, declaredMax, buffer.byteLength(), buffer.wasmMaxSize(),
     726           0 :                          metadata().isAsmJS(), "Memory")) {
     727           0 :             return false;
     728             :         }
     729             :     } else {
     730           0 :         MOZ_ASSERT(!metadata().isAsmJS());
     731           0 :         MOZ_ASSERT(metadata().memoryUsage == MemoryUsage::Unshared);
     732             : 
     733             :         RootedArrayBufferObjectMaybeShared buffer(cx,
     734           0 :             ArrayBufferObject::createForWasm(cx, declaredMin, declaredMax));
     735           0 :         if (!buffer)
     736           0 :             return false;
     737             : 
     738           0 :         RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmMemory).toObject());
     739             : 
     740           0 :         memory.set(WasmMemoryObject::create(cx, buffer, proto));
     741           0 :         if (!memory)
     742           0 :             return false;
     743             :     }
     744             : 
     745           0 :     return true;
     746             : }
     747             : 
     748             : bool
     749           0 : Module::instantiateTable(JSContext* cx, MutableHandleWasmTableObject tableObj,
     750             :                          SharedTableVector* tables) const
     751             : {
     752           0 :     if (tableObj) {
     753           0 :         MOZ_ASSERT(!metadata().isAsmJS());
     754             : 
     755           0 :         MOZ_ASSERT(metadata().tables.length() == 1);
     756           0 :         const TableDesc& td = metadata().tables[0];
     757           0 :         MOZ_ASSERT(td.external);
     758             : 
     759           0 :         Table& table = tableObj->table();
     760           0 :         if (!CheckLimits(cx, td.limits.initial, td.limits.maximum, table.length(), table.maximum(),
     761           0 :                          metadata().isAsmJS(), "Table")) {
     762           0 :             return false;
     763             :         }
     764             : 
     765           0 :         if (!tables->append(&table)) {
     766           0 :             ReportOutOfMemory(cx);
     767           0 :             return false;
     768             :         }
     769             :     } else {
     770           0 :         for (const TableDesc& td : metadata().tables) {
     771           0 :             SharedTable table;
     772           0 :             if (td.external) {
     773           0 :                 MOZ_ASSERT(!tableObj);
     774           0 :                 MOZ_ASSERT(td.kind == TableKind::AnyFunction);
     775             : 
     776           0 :                 tableObj.set(WasmTableObject::create(cx, td.limits));
     777           0 :                 if (!tableObj)
     778           0 :                     return false;
     779             : 
     780           0 :                 table = &tableObj->table();
     781             :             } else {
     782           0 :                 table = Table::create(cx, td, /* HandleWasmTableObject = */ nullptr);
     783           0 :                 if (!table)
     784           0 :                     return false;
     785             :             }
     786             : 
     787           0 :             if (!tables->emplaceBack(table)) {
     788           0 :                 ReportOutOfMemory(cx);
     789           0 :                 return false;
     790             :             }
     791             :         }
     792             :     }
     793             : 
     794           0 :     return true;
     795             : }
     796             : 
     797             : static bool
     798           0 : GetFunctionExport(JSContext* cx,
     799             :                   HandleWasmInstanceObject instanceObj,
     800             :                   Handle<FunctionVector> funcImports,
     801             :                   const Export& exp,
     802             :                   MutableHandleValue val)
     803             : {
     804           0 :     if (exp.funcIndex() < funcImports.length() &&
     805           0 :         IsExportedWasmFunction(funcImports[exp.funcIndex()]))
     806             :     {
     807           0 :         val.setObject(*funcImports[exp.funcIndex()]);
     808           0 :         return true;
     809             :     }
     810             : 
     811           0 :     RootedFunction fun(cx);
     812           0 :     if (!instanceObj->getExportedFunction(cx, instanceObj, exp.funcIndex(), &fun))
     813           0 :         return false;
     814             : 
     815           0 :     val.setObject(*fun);
     816           0 :     return true;
     817             : }
     818             : 
     819             : static bool
     820           0 : GetGlobalExport(JSContext* cx, const GlobalDescVector& globals, uint32_t globalIndex,
     821             :                 const ValVector& globalImports, MutableHandleValue jsval)
     822             : {
     823           0 :     const GlobalDesc& global = globals[globalIndex];
     824             : 
     825             :     // Imports are located upfront in the globals array.
     826           0 :     Val val;
     827           0 :     switch (global.kind()) {
     828           0 :       case GlobalKind::Import:   val = globalImports[globalIndex]; break;
     829           0 :       case GlobalKind::Variable: MOZ_CRASH("mutable variables can't be exported");
     830           0 :       case GlobalKind::Constant: val = global.constantValue(); break;
     831             :     }
     832             : 
     833           0 :     switch (global.type()) {
     834             :       case ValType::I32: {
     835           0 :         jsval.set(Int32Value(val.i32()));
     836           0 :         return true;
     837             :       }
     838             :       case ValType::I64: {
     839           0 :         MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
     840           0 :         RootedObject obj(cx, CreateI64Object(cx, val.i64()));
     841           0 :         if (!obj)
     842           0 :             return false;
     843           0 :         jsval.set(ObjectValue(*obj));
     844           0 :         return true;
     845             :       }
     846             :       case ValType::F32: {
     847           0 :         float f = val.f32();
     848           0 :         if (JitOptions.wasmTestMode && IsNaN(f)) {
     849           0 :             RootedObject obj(cx, CreateCustomNaNObject(cx, &f));
     850           0 :             if (!obj)
     851           0 :                 return false;
     852           0 :             jsval.set(ObjectValue(*obj));
     853           0 :             return true;
     854             :         }
     855           0 :         jsval.set(DoubleValue(double(f)));
     856           0 :         return true;
     857             :       }
     858             :       case ValType::F64: {
     859           0 :         double d = val.f64();
     860           0 :         if (JitOptions.wasmTestMode && IsNaN(d)) {
     861           0 :             RootedObject obj(cx, CreateCustomNaNObject(cx, &d));
     862           0 :             if (!obj)
     863           0 :                 return false;
     864           0 :             jsval.set(ObjectValue(*obj));
     865           0 :             return true;
     866             :         }
     867           0 :         jsval.set(DoubleValue(d));
     868           0 :         return true;
     869             :       }
     870             :       default: {
     871           0 :         break;
     872             :       }
     873             :     }
     874           0 :     MOZ_CRASH("unexpected type when creating global exports");
     875             : }
     876             : 
     877             : static bool
     878           0 : CreateExportObject(JSContext* cx,
     879             :                    HandleWasmInstanceObject instanceObj,
     880             :                    Handle<FunctionVector> funcImports,
     881             :                    HandleWasmTableObject tableObj,
     882             :                    HandleWasmMemoryObject memoryObj,
     883             :                    const ValVector& globalImports,
     884             :                    const ExportVector& exports)
     885             : {
     886           0 :     const Instance& instance = instanceObj->instance();
     887           0 :     const Metadata& metadata = instance.metadata();
     888             : 
     889           0 :     if (metadata.isAsmJS() && exports.length() == 1 && strlen(exports[0].fieldName()) == 0) {
     890           0 :         RootedValue val(cx);
     891           0 :         if (!GetFunctionExport(cx, instanceObj, funcImports, exports[0], &val))
     892           0 :             return false;
     893           0 :         instanceObj->initExportsObj(val.toObject());
     894           0 :         return true;
     895             :     }
     896             : 
     897           0 :     RootedObject exportObj(cx);
     898           0 :     if (metadata.isAsmJS())
     899           0 :         exportObj = NewBuiltinClassInstance<PlainObject>(cx);
     900             :     else
     901           0 :         exportObj = NewObjectWithGivenProto<PlainObject>(cx, nullptr);
     902           0 :     if (!exportObj)
     903           0 :         return false;
     904             : 
     905           0 :     for (const Export& exp : exports) {
     906           0 :         JSAtom* atom = AtomizeUTF8Chars(cx, exp.fieldName(), strlen(exp.fieldName()));
     907           0 :         if (!atom)
     908           0 :             return false;
     909             : 
     910           0 :         RootedId id(cx, AtomToId(atom));
     911           0 :         RootedValue val(cx);
     912           0 :         switch (exp.kind()) {
     913             :           case DefinitionKind::Function:
     914           0 :             if (!GetFunctionExport(cx, instanceObj, funcImports, exp, &val))
     915           0 :                 return false;
     916           0 :             break;
     917             :           case DefinitionKind::Table:
     918           0 :             val = ObjectValue(*tableObj);
     919           0 :             break;
     920             :           case DefinitionKind::Memory:
     921           0 :             val = ObjectValue(*memoryObj);
     922           0 :             break;
     923             :           case DefinitionKind::Global:
     924           0 :             if (!GetGlobalExport(cx, metadata.globals, exp.globalIndex(), globalImports, &val))
     925           0 :                 return false;
     926           0 :             break;
     927             :         }
     928             : 
     929           0 :         if (!JS_DefinePropertyById(cx, exportObj, id, val, JSPROP_ENUMERATE))
     930           0 :             return false;
     931             :     }
     932             : 
     933           0 :     if (!metadata.isAsmJS()) {
     934           0 :         if (!JS_FreezeObject(cx, exportObj))
     935           0 :             return false;
     936             :     }
     937             : 
     938           0 :     instanceObj->initExportsObj(*exportObj);
     939           0 :     return true;
     940             : }
     941             : 
     942             : bool
     943           0 : Module::instantiate(JSContext* cx,
     944             :                     Handle<FunctionVector> funcImports,
     945             :                     HandleWasmTableObject tableImport,
     946             :                     HandleWasmMemoryObject memoryImport,
     947             :                     const ValVector& globalImports,
     948             :                     HandleObject instanceProto,
     949             :                     MutableHandleWasmInstanceObject instance) const
     950             : {
     951           0 :     if (!instantiateFunctions(cx, funcImports))
     952           0 :         return false;
     953             : 
     954           0 :     RootedWasmMemoryObject memory(cx, memoryImport);
     955           0 :     if (!instantiateMemory(cx, &memory))
     956           0 :         return false;
     957             : 
     958           0 :     RootedWasmTableObject table(cx, tableImport);
     959           0 :     SharedTableVector tables;
     960           0 :     if (!instantiateTable(cx, &table, &tables))
     961           0 :         return false;
     962             : 
     963           0 :     auto globalSegment = GlobalSegment::create(metadata().globalDataLength);
     964           0 :     if (!globalSegment) {
     965           0 :         ReportOutOfMemory(cx);
     966           0 :         return false;
     967             :     }
     968             : 
     969           0 :     SharedCode code(code_);
     970             : 
     971           0 :     if (metadata().debugEnabled) {
     972             :         // The first time through, use the pre-linked code in the module but
     973             :         // mark it as busy. Subsequently, instantiate the copy of the code
     974             :         // bytes that we keep around for debugging instead, because the debugger
     975             :         // may patch the pre-linked code at any time.
     976           0 :         if (!codeIsBusy_.compareExchange(false, true)) {
     977             :             auto codeSegment = CodeSegment::create(Tier::Baseline,
     978           0 :                                                    *unlinkedCodeForDebugging_,
     979             :                                                    *bytecode_,
     980             :                                                    linkData_.linkData(Tier::Baseline),
     981           0 :                                                    metadata());
     982           0 :             if (!codeSegment) {
     983           0 :                 ReportOutOfMemory(cx);
     984           0 :                 return false;
     985             :             }
     986             : 
     987           0 :             code = js_new<Code>(Move(codeSegment), metadata());
     988           0 :             if (!code) {
     989           0 :                 ReportOutOfMemory(cx);
     990           0 :                 return false;
     991             :             }
     992             :         }
     993             :     }
     994             : 
     995             :     // To support viewing the source of an instance (Instance::createText), the
     996             :     // instance must hold onto a ref of the bytecode (keeping it alive). This
     997             :     // wastes memory for most users, so we try to only save the source when a
     998             :     // developer actually cares: when the compartment is debuggable (which is
     999             :     // true when the web console is open), has code compiled with debug flag
    1000             :     // enabled or a names section is present (since this going to be stripped
    1001             :     // for non-developer builds).
    1002             : 
    1003           0 :     const ShareableBytes* maybeBytecode = nullptr;
    1004           0 :     if (cx->compartment()->isDebuggee() || metadata().debugEnabled ||
    1005           0 :         !metadata().funcNames.empty())
    1006             :     {
    1007           0 :         maybeBytecode = bytecode_.get();
    1008             :     }
    1009             : 
    1010             :     // The debug object must be present even when debugging is not enabled: It
    1011             :     // provides the lazily created source text for the program, even if that
    1012             :     // text is a placeholder message when debugging is not enabled.
    1013             : 
    1014           0 :     bool binarySource = cx->compartment()->debuggerObservesBinarySource();
    1015           0 :     auto debug = cx->make_unique<DebugState>(code, maybeBytecode, binarySource);
    1016           0 :     if (!debug)
    1017           0 :         return false;
    1018             : 
    1019           0 :     instance.set(WasmInstanceObject::create(cx,
    1020             :                                             code,
    1021           0 :                                             Move(debug),
    1022           0 :                                             Move(globalSegment),
    1023             :                                             memory,
    1024           0 :                                             Move(tables),
    1025             :                                             funcImports,
    1026             :                                             globalImports,
    1027           0 :                                             instanceProto));
    1028           0 :     if (!instance)
    1029           0 :         return false;
    1030             : 
    1031           0 :     if (!CreateExportObject(cx, instance, funcImports, table, memory, globalImports, exports_))
    1032           0 :         return false;
    1033             : 
    1034             :     // Register the instance with the JSCompartment so that it can find out
    1035             :     // about global events like profiling being enabled in the compartment.
    1036             :     // Registration does not require a fully-initialized instance and must
    1037             :     // precede initSegments as the final pre-requisite for a live instance.
    1038             : 
    1039           0 :     if (!cx->compartment()->wasm.registerInstance(cx, instance))
    1040           0 :         return false;
    1041             : 
    1042             :     // Perform initialization as the final step after the instance is fully
    1043             :     // constructed since this can make the instance live to content (even if the
    1044             :     // start function fails).
    1045             : 
    1046           0 :     if (!initSegments(cx, instance, funcImports, memory, globalImports))
    1047           0 :         return false;
    1048             : 
    1049             :     // Now that the instance is fully live and initialized, the start function.
    1050             :     // Note that failure may cause instantiation to throw, but the instance may
    1051             :     // still be live via edges created by initSegments or the start function.
    1052             : 
    1053           0 :     if (metadata().startFuncIndex) {
    1054           0 :         FixedInvokeArgs<0> args(cx);
    1055           0 :         if (!instance->instance().callExport(cx, *metadata().startFuncIndex, args))
    1056           0 :             return false;
    1057             :     }
    1058             : 
    1059           0 :     uint32_t mode = uint32_t(metadata().isAsmJS() ? Telemetry::ASMJS : Telemetry::WASM);
    1060           0 :     cx->runtime()->addTelemetry(JS_TELEMETRY_AOT_USAGE, mode);
    1061             : 
    1062           0 :     return true;
    1063             : }

Generated by: LCOV version 1.13