1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
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 <chrono>
22 
23 #include "js/BuildId.h"                 // JS::BuildIdCharVector
24 #include "js/experimental/TypedData.h"  // JS_NewUint8Array
25 #include "js/friend/ErrorMessages.h"    // js::GetErrorMessage, JSMSG_*
26 #include "js/Printf.h"                  // JS_smprintf
27 #include "js/PropertyAndElement.h"  // JS_DefineProperty, JS_DefinePropertyById
28 #include "js/StreamConsumer.h"
29 #include "threading/LockGuard.h"
30 #include "vm/HelperThreadState.h"  // Tier2GeneratorTask
31 #include "vm/PlainObject.h"        // js::PlainObject
32 #include "wasm/WasmBaselineCompile.h"
33 #include "wasm/WasmCompile.h"
34 #include "wasm/WasmInstance.h"
35 #include "wasm/WasmIonCompile.h"
36 #include "wasm/WasmJS.h"
37 #include "wasm/WasmSerialize.h"
38 #include "wasm/WasmUtility.h"
39 
40 #include "debugger/DebugAPI-inl.h"
41 #include "vm/ArrayBufferObject-inl.h"
42 #include "vm/JSAtom-inl.h"
43 
44 using namespace js;
45 using namespace js::jit;
46 using namespace js::wasm;
47 
Tier2ResultsContext(const ScriptedCaller & scriptedCaller)48 static UniqueChars Tier2ResultsContext(const ScriptedCaller& scriptedCaller) {
49   return scriptedCaller.filename
50              ? JS_smprintf("%s:%d", scriptedCaller.filename.get(),
51                            scriptedCaller.line)
52              : UniqueChars();
53 }
54 
ReportTier2ResultsOffThread(bool success,const ScriptedCaller & scriptedCaller,const UniqueChars & error,const UniqueCharsVector & warnings)55 static void ReportTier2ResultsOffThread(bool success,
56                                         const ScriptedCaller& scriptedCaller,
57                                         const UniqueChars& error,
58                                         const UniqueCharsVector& warnings) {
59   // Get context to describe this tier-2 task.
60   UniqueChars context = Tier2ResultsContext(scriptedCaller);
61   const char* contextString = context ? context.get() : "unknown";
62 
63   // Display the main error, if any.
64   if (!success) {
65     const char* errorString = error ? error.get() : "out of memory";
66     LogOffThread("'%s': wasm tier-2 failed with '%s'.\n", contextString,
67                  errorString);
68   }
69 
70   // Display warnings as a follow-up, avoiding spamming the console.
71   size_t numWarnings = std::min<size_t>(warnings.length(), 3);
72 
73   for (size_t i = 0; i < numWarnings; i++) {
74     LogOffThread("'%s': wasm tier-2 warning: '%s'.\n'.", contextString,
75                  warnings[i].get());
76   }
77   if (warnings.length() > numWarnings) {
78     LogOffThread("'%s': other warnings suppressed.\n", contextString);
79   }
80 }
81 
82 class Module::Tier2GeneratorTaskImpl : public Tier2GeneratorTask {
83   SharedCompileArgs compileArgs_;
84   SharedBytes bytecode_;
85   SharedModule module_;
86   Atomic<bool> cancelled_;
87 
88  public:
Tier2GeneratorTaskImpl(const CompileArgs & compileArgs,const ShareableBytes & bytecode,Module & module)89   Tier2GeneratorTaskImpl(const CompileArgs& compileArgs,
90                          const ShareableBytes& bytecode, Module& module)
91       : compileArgs_(&compileArgs),
92         bytecode_(&bytecode),
93         module_(&module),
94         cancelled_(false) {}
95 
~Tier2GeneratorTaskImpl()96   ~Tier2GeneratorTaskImpl() override {
97     module_->tier2Listener_ = nullptr;
98     module_->testingTier2Active_ = false;
99   }
100 
cancel()101   void cancel() override { cancelled_ = true; }
102 
runHelperThreadTask(AutoLockHelperThreadState & locked)103   void runHelperThreadTask(AutoLockHelperThreadState& locked) override {
104     {
105       AutoUnlockHelperThreadState unlock(locked);
106 
107       // Compile tier-2 and report any warning/errors as long as it's not a
108       // cancellation. Encountering a warning/error during compilation and
109       // being cancelled may race with each other, but the only observable race
110       // should be being cancelled after a warning/error is set, and that's
111       // okay.
112       UniqueChars error;
113       UniqueCharsVector warnings;
114       bool success = CompileTier2(*compileArgs_, bytecode_->bytes, *module_,
115                                   &error, &warnings, &cancelled_);
116       if (!cancelled_) {
117         // We could try to dispatch a runnable to the thread that started this
118         // compilation, so as to report the warning/error using a JSContext*.
119         // For now we just report to stderr.
120         ReportTier2ResultsOffThread(success, compileArgs_->scriptedCaller,
121                                     error, warnings);
122       }
123     }
124 
125     // During shutdown the main thread will wait for any ongoing (cancelled)
126     // tier-2 generation to shut down normally.  To do so, it waits on the
127     // HelperThreadState's condition variable for the count of finished
128     // generators to rise.
129     HelperThreadState().incWasmTier2GeneratorsFinished(locked);
130 
131     // The task is finished, release it.
132     js_delete(this);
133   }
134 
threadType()135   ThreadType threadType() override {
136     return ThreadType::THREAD_TYPE_WASM_GENERATOR_TIER2;
137   }
138 };
139 
~Module()140 Module::~Module() {
141   // Note: Modules can be destroyed on any thread.
142   MOZ_ASSERT(!tier2Listener_);
143   MOZ_ASSERT(!testingTier2Active_);
144 }
145 
startTier2(const CompileArgs & args,const ShareableBytes & bytecode,JS::OptimizedEncodingListener * listener)146 void Module::startTier2(const CompileArgs& args, const ShareableBytes& bytecode,
147                         JS::OptimizedEncodingListener* listener) {
148   MOZ_ASSERT(!testingTier2Active_);
149 
150   auto task = MakeUnique<Tier2GeneratorTaskImpl>(args, bytecode, *this);
151   if (!task) {
152     return;
153   }
154 
155   // These will be cleared asynchronously by ~Tier2GeneratorTaskImpl() if not
156   // sooner by finishTier2().
157   tier2Listener_ = listener;
158   testingTier2Active_ = true;
159 
160   StartOffThreadWasmTier2Generator(std::move(task));
161 }
162 
finishTier2(const LinkData & linkData2,UniqueCodeTier code2) const163 bool Module::finishTier2(const LinkData& linkData2,
164                          UniqueCodeTier code2) const {
165   MOZ_ASSERT(code().bestTier() == Tier::Baseline &&
166              code2->tier() == Tier::Optimized);
167 
168   // Install the data in the data structures. They will not be visible
169   // until commitTier2().
170 
171   const CodeTier* borrowedTier2;
172   if (!code().setAndBorrowTier2(std::move(code2), linkData2, &borrowedTier2)) {
173     return false;
174   }
175 
176   // Before we can make tier-2 live, we need to compile tier2 versions of any
177   // extant tier1 lazy stubs (otherwise, tiering would break the assumption
178   // that any extant exported wasm function has had a lazy entry stub already
179   // compiled for it).
180   //
181   // Also see doc block for stubs in WasmJS.cpp.
182   {
183     // We need to prevent new tier1 stubs generation until we've committed
184     // the newer tier2 stubs, otherwise we might not generate one tier2
185     // stub that has been generated for tier1 before we committed.
186 
187     const MetadataTier& metadataTier1 = metadata(Tier::Baseline);
188 
189     auto stubs1 = code().codeTier(Tier::Baseline).lazyStubs().readLock();
190     auto stubs2 = borrowedTier2->lazyStubs().writeLock();
191 
192     MOZ_ASSERT(stubs2->entryStubsEmpty());
193 
194     Uint32Vector funcExportIndices;
195     for (size_t i = 0; i < metadataTier1.funcExports.length(); i++) {
196       const FuncExport& fe = metadataTier1.funcExports[i];
197       if (fe.hasEagerStubs()) {
198         continue;
199       }
200       if (!stubs1->hasEntryStub(fe.funcIndex())) {
201         continue;
202       }
203       if (!funcExportIndices.emplaceBack(i)) {
204         return false;
205       }
206     }
207 
208     Maybe<size_t> stub2Index;
209     if (!stubs2->createTier2(funcExportIndices, *borrowedTier2, &stub2Index)) {
210       return false;
211     }
212 
213     // Now that we can't fail or otherwise abort tier2, make it live.
214 
215     MOZ_ASSERT(!code().hasTier2());
216     code().commitTier2();
217 
218     stubs2->setJitEntries(stub2Index, code());
219   }
220 
221   // And we update the jump vectors with pointers to tier-2 functions and eager
222   // stubs.  Callers will continue to invoke tier-1 code until, suddenly, they
223   // will invoke tier-2 code.  This is benign.
224 
225   uint8_t* base = code().segment(Tier::Optimized).base();
226   for (const CodeRange& cr : metadata(Tier::Optimized).codeRanges) {
227     // These are racy writes that we just want to be visible, atomically,
228     // eventually.  All hardware we care about will do this right.  But
229     // we depend on the compiler not splitting the stores hidden inside the
230     // set*Entry functions.
231     if (cr.isFunction()) {
232       code().setTieringEntry(cr.funcIndex(), base + cr.funcTierEntry());
233     } else if (cr.isJitEntry()) {
234       code().setJitEntry(cr.funcIndex(), base + cr.begin());
235     }
236   }
237 
238   // Tier-2 is done; let everyone know. Mark tier-2 active for testing
239   // purposes so that wasmHasTier2CompilationCompleted() only returns true
240   // after tier-2 has been fully cached.
241 
242   if (tier2Listener_) {
243     serialize(linkData2, *tier2Listener_);
244     tier2Listener_ = nullptr;
245   }
246   testingTier2Active_ = false;
247 
248   return true;
249 }
250 
testingBlockOnTier2Complete() const251 void Module::testingBlockOnTier2Complete() const {
252   while (testingTier2Active_) {
253     ThisThread::SleepMilliseconds(1);
254   }
255 }
256 
257 /* virtual */
serializedSize(const LinkData & linkData) const258 size_t Module::serializedSize(const LinkData& linkData) const {
259   JS::BuildIdCharVector buildId;
260   {
261     AutoEnterOOMUnsafeRegion oom;
262     if (!GetOptimizedEncodingBuildId(&buildId)) {
263       oom.crash("getting build id");
264     }
265   }
266 
267   return SerializedPodVectorSize(buildId) + linkData.serializedSize() +
268          SerializedVectorSize(imports_) + SerializedVectorSize(exports_) +
269          SerializedVectorSize(dataSegments_) +
270          SerializedVectorSize(elemSegments_) +
271          SerializedVectorSize(customSections_) + code_->serializedSize();
272 }
273 
274 /* virtual */
serialize(const LinkData & linkData,uint8_t * begin,size_t size) const275 void Module::serialize(const LinkData& linkData, uint8_t* begin,
276                        size_t size) const {
277   MOZ_RELEASE_ASSERT(!metadata().debugEnabled);
278   MOZ_RELEASE_ASSERT(code_->hasTier(Tier::Serialized));
279 
280   JS::BuildIdCharVector buildId;
281   {
282     AutoEnterOOMUnsafeRegion oom;
283     if (!GetOptimizedEncodingBuildId(&buildId)) {
284       oom.crash("getting build id");
285     }
286   }
287 
288   uint8_t* cursor = begin;
289   cursor = SerializePodVector(cursor, buildId);
290   cursor = linkData.serialize(cursor);
291   cursor = SerializeVector(cursor, imports_);
292   cursor = SerializeVector(cursor, exports_);
293   cursor = SerializeVector(cursor, dataSegments_);
294   cursor = SerializeVector(cursor, elemSegments_);
295   cursor = SerializeVector(cursor, customSections_);
296   cursor = code_->serialize(cursor, linkData);
297   MOZ_RELEASE_ASSERT(cursor == begin + size);
298 }
299 
300 /* static */
deserialize(const uint8_t * begin,size_t size,Metadata * maybeMetadata)301 MutableModule Module::deserialize(const uint8_t* begin, size_t size,
302                                   Metadata* maybeMetadata) {
303   MutableMetadata metadata(maybeMetadata);
304   if (!metadata) {
305     metadata = js_new<Metadata>();
306     if (!metadata) {
307       return nullptr;
308     }
309   }
310 
311   const uint8_t* cursor = begin;
312 
313   JS::BuildIdCharVector currentBuildId;
314   if (!GetOptimizedEncodingBuildId(&currentBuildId)) {
315     return nullptr;
316   }
317 
318   JS::BuildIdCharVector deserializedBuildId;
319   cursor = DeserializePodVector(cursor, &deserializedBuildId);
320   if (!cursor) {
321     return nullptr;
322   }
323 
324   MOZ_RELEASE_ASSERT(EqualContainers(currentBuildId, deserializedBuildId));
325 
326   LinkData linkData(Tier::Serialized);
327   cursor = linkData.deserialize(cursor);
328   if (!cursor) {
329     return nullptr;
330   }
331 
332   ImportVector imports;
333   cursor = DeserializeVector(cursor, &imports);
334   if (!cursor) {
335     return nullptr;
336   }
337 
338   ExportVector exports;
339   cursor = DeserializeVector(cursor, &exports);
340   if (!cursor) {
341     return nullptr;
342   }
343 
344   DataSegmentVector dataSegments;
345   cursor = DeserializeVector(cursor, &dataSegments);
346   if (!cursor) {
347     return nullptr;
348   }
349 
350   ElemSegmentVector elemSegments;
351   cursor = DeserializeVector(cursor, &elemSegments);
352   if (!cursor) {
353     return nullptr;
354   }
355 
356   CustomSectionVector customSections;
357   cursor = DeserializeVector(cursor, &customSections);
358   if (!cursor) {
359     return nullptr;
360   }
361 
362   SharedCode code;
363   cursor = Code::deserialize(cursor, linkData, *metadata, &code);
364   if (!cursor) {
365     return nullptr;
366   }
367 
368   MOZ_RELEASE_ASSERT(cursor == begin + size);
369   MOZ_RELEASE_ASSERT(!!maybeMetadata == code->metadata().isAsmJS());
370 
371   if (metadata->nameCustomSectionIndex) {
372     metadata->namePayload =
373         customSections[*metadata->nameCustomSectionIndex].payload;
374   } else {
375     MOZ_RELEASE_ASSERT(!metadata->moduleName);
376     MOZ_RELEASE_ASSERT(metadata->funcNames.empty());
377   }
378 
379   return js_new<Module>(*code, std::move(imports), std::move(exports),
380                         std::move(dataSegments), std::move(elemSegments),
381                         std::move(customSections), nullptr, nullptr, nullptr,
382                         /* loggingDeserialized = */ true);
383 }
384 
serialize(const LinkData & linkData,JS::OptimizedEncodingListener & listener) const385 void Module::serialize(const LinkData& linkData,
386                        JS::OptimizedEncodingListener& listener) const {
387   Bytes bytes;
388   if (!bytes.resizeUninitialized(serializedSize(linkData))) {
389     return;
390   }
391 
392   serialize(linkData, bytes.begin(), bytes.length());
393 
394   listener.storeOptimizedEncoding(bytes.begin(), bytes.length());
395 }
396 
397 /* virtual */
createObject(JSContext * cx) const398 JSObject* Module::createObject(JSContext* cx) const {
399   if (!GlobalObject::ensureConstructor(cx, cx->global(), JSProto_WebAssembly)) {
400     return nullptr;
401   }
402 
403   RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmModule));
404   return WasmModuleObject::create(cx, *this, proto);
405 }
406 
407 /* virtual */
createObjectForAsmJS(JSContext * cx) const408 JSObject* Module::createObjectForAsmJS(JSContext* cx) const {
409   // Use nullptr to get the default object prototype. These objects are never
410   // exposed to script for asm.js.
411   return WasmModuleObject::create(cx, *this, nullptr);
412 }
413 
GetOptimizedEncodingBuildId(JS::BuildIdCharVector * buildId)414 bool wasm::GetOptimizedEncodingBuildId(JS::BuildIdCharVector* buildId) {
415   // From a JS API perspective, the "build id" covers everything that can
416   // cause machine code to become invalid, so include both the actual build-id
417   // and cpu-id.
418 
419   if (!GetBuildId || !GetBuildId(buildId)) {
420     return false;
421   }
422 
423   uint32_t cpu = ObservedCPUFeatures();
424 
425   if (!buildId->reserve(buildId->length() +
426                         13 /* "()" + 8 nibbles + "m[+-][+-]" */)) {
427     return false;
428   }
429 
430   buildId->infallibleAppend('(');
431   while (cpu) {
432     buildId->infallibleAppend('0' + (cpu & 0xf));
433     cpu >>= 4;
434   }
435   buildId->infallibleAppend(')');
436 
437   buildId->infallibleAppend('m');
438   buildId->infallibleAppend(wasm::IsHugeMemoryEnabled(IndexType::I32) ? '+'
439                                                                       : '-');
440   buildId->infallibleAppend(wasm::IsHugeMemoryEnabled(IndexType::I64) ? '+'
441                                                                       : '-');
442 
443   return true;
444 }
445 
446 /* virtual */
addSizeOfMisc(MallocSizeOf mallocSizeOf,Metadata::SeenSet * seenMetadata,Code::SeenSet * seenCode,size_t * code,size_t * data) const447 void Module::addSizeOfMisc(MallocSizeOf mallocSizeOf,
448                            Metadata::SeenSet* seenMetadata,
449                            Code::SeenSet* seenCode, size_t* code,
450                            size_t* data) const {
451   code_->addSizeOfMiscIfNotSeen(mallocSizeOf, seenMetadata, seenCode, code,
452                                 data);
453   *data += mallocSizeOf(this) +
454            SizeOfVectorExcludingThis(imports_, mallocSizeOf) +
455            SizeOfVectorExcludingThis(exports_, mallocSizeOf) +
456            SizeOfVectorExcludingThis(dataSegments_, mallocSizeOf) +
457            SizeOfVectorExcludingThis(elemSegments_, mallocSizeOf) +
458            SizeOfVectorExcludingThis(customSections_, mallocSizeOf);
459 
460   if (debugUnlinkedCode_) {
461     *data += debugUnlinkedCode_->sizeOfExcludingThis(mallocSizeOf);
462   }
463 }
464 
initGCMallocBytesExcludingCode()465 void Module::initGCMallocBytesExcludingCode() {
466   // The size doesn't have to be exact so use the serialization framework to
467   // calculate a value.
468   gcMallocBytesExcludingCode_ = sizeof(*this) + SerializedVectorSize(imports_) +
469                                 SerializedVectorSize(exports_) +
470                                 SerializedVectorSize(dataSegments_) +
471                                 SerializedVectorSize(elemSegments_) +
472                                 SerializedVectorSize(customSections_);
473 }
474 
475 // Extracting machine code as JS object. The result has the "code" property, as
476 // a Uint8Array, and the "segments" property as array objects. The objects
477 // contain offsets in the "code" array and basic information about a code
478 // segment/function body.
extractCode(JSContext * cx,Tier tier,MutableHandleValue vp) const479 bool Module::extractCode(JSContext* cx, Tier tier,
480                          MutableHandleValue vp) const {
481   RootedPlainObject result(cx, NewPlainObject(cx));
482   if (!result) {
483     return false;
484   }
485 
486   // This function is only used for testing purposes so we can simply
487   // block on tiered compilation to complete.
488   testingBlockOnTier2Complete();
489 
490   if (!code_->hasTier(tier)) {
491     vp.setNull();
492     return true;
493   }
494 
495   const ModuleSegment& moduleSegment = code_->segment(tier);
496   RootedObject code(cx, JS_NewUint8Array(cx, moduleSegment.length()));
497   if (!code) {
498     return false;
499   }
500 
501   memcpy(code->as<TypedArrayObject>().dataPointerUnshared(),
502          moduleSegment.base(), moduleSegment.length());
503 
504   RootedValue value(cx, ObjectValue(*code));
505   if (!JS_DefineProperty(cx, result, "code", value, JSPROP_ENUMERATE)) {
506     return false;
507   }
508 
509   RootedObject segments(cx, NewDenseEmptyArray(cx));
510   if (!segments) {
511     return false;
512   }
513 
514   for (const CodeRange& p : metadata(tier).codeRanges) {
515     RootedObject segment(cx, NewPlainObjectWithProto(cx, nullptr));
516     if (!segment) {
517       return false;
518     }
519 
520     value.setNumber((uint32_t)p.begin());
521     if (!JS_DefineProperty(cx, segment, "begin", value, JSPROP_ENUMERATE)) {
522       return false;
523     }
524 
525     value.setNumber((uint32_t)p.end());
526     if (!JS_DefineProperty(cx, segment, "end", value, JSPROP_ENUMERATE)) {
527       return false;
528     }
529 
530     value.setNumber((uint32_t)p.kind());
531     if (!JS_DefineProperty(cx, segment, "kind", value, JSPROP_ENUMERATE)) {
532       return false;
533     }
534 
535     if (p.isFunction()) {
536       value.setNumber((uint32_t)p.funcIndex());
537       if (!JS_DefineProperty(cx, segment, "funcIndex", value,
538                              JSPROP_ENUMERATE)) {
539         return false;
540       }
541 
542       value.setNumber((uint32_t)p.funcUncheckedCallEntry());
543       if (!JS_DefineProperty(cx, segment, "funcBodyBegin", value,
544                              JSPROP_ENUMERATE)) {
545         return false;
546       }
547 
548       value.setNumber((uint32_t)p.end());
549       if (!JS_DefineProperty(cx, segment, "funcBodyEnd", value,
550                              JSPROP_ENUMERATE)) {
551         return false;
552       }
553     }
554 
555     if (!NewbornArrayPush(cx, segments, ObjectValue(*segment))) {
556       return false;
557     }
558   }
559 
560   value.setObject(*segments);
561   if (!JS_DefineProperty(cx, result, "segments", value, JSPROP_ENUMERATE)) {
562     return false;
563   }
564 
565   vp.setObject(*result);
566   return true;
567 }
568 
569 #ifdef DEBUG
AllSegmentsArePassive(const DataSegmentVector & vec)570 static bool AllSegmentsArePassive(const DataSegmentVector& vec) {
571   for (const DataSegment* seg : vec) {
572     if (seg->active()) {
573       return false;
574     }
575   }
576   return true;
577 }
578 #endif
579 
initSegments(JSContext * cx,HandleWasmInstanceObject instanceObj,HandleWasmMemoryObject memoryObj,const ValVector & globalImportValues) const580 bool Module::initSegments(JSContext* cx, HandleWasmInstanceObject instanceObj,
581                           HandleWasmMemoryObject memoryObj,
582                           const ValVector& globalImportValues) const {
583   MOZ_ASSERT_IF(!memoryObj, AllSegmentsArePassive(dataSegments_));
584 
585   Instance& instance = instanceObj->instance();
586   const SharedTableVector& tables = instance.tables();
587 
588   // Write data/elem segments into memories/tables.
589 
590   for (const ElemSegment* seg : elemSegments_) {
591     if (seg->active()) {
592       RootedVal offsetVal(cx);
593       if (!seg->offset().evaluate(cx, globalImportValues, instanceObj,
594                                   &offsetVal)) {
595         return false;  // OOM
596       }
597       uint32_t offset = offsetVal.get().i32();
598       uint32_t count = seg->length();
599 
600       uint32_t tableLength = tables[seg->tableIndex]->length();
601       if (offset > tableLength || tableLength - offset < count) {
602         JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
603                                  JSMSG_WASM_OUT_OF_BOUNDS);
604         return false;
605       }
606 
607       if (!instance.initElems(seg->tableIndex, *seg, offset, 0, count)) {
608         return false;  // OOM
609       }
610     }
611   }
612 
613   if (memoryObj) {
614     size_t memoryLength = memoryObj->volatileMemoryLength();
615     uint8_t* memoryBase =
616         memoryObj->buffer().dataPointerEither().unwrap(/* memcpy */);
617 
618     for (const DataSegment* seg : dataSegments_) {
619       if (!seg->active()) {
620         continue;
621       }
622 
623       RootedVal offsetVal(cx);
624       if (!seg->offset().evaluate(cx, globalImportValues, instanceObj,
625                                   &offsetVal)) {
626         return false;  // OOM
627       }
628       uint64_t offset = memoryObj->indexType() == IndexType::I32
629                             ? offsetVal.get().i32()
630                             : offsetVal.get().i64();
631       uint32_t count = seg->bytes.length();
632 
633       if (offset > memoryLength || memoryLength - offset < count) {
634         JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
635                                  JSMSG_WASM_OUT_OF_BOUNDS);
636         return false;
637       }
638       memcpy(memoryBase + uintptr_t(offset), seg->bytes.begin(), count);
639     }
640   }
641 
642   return true;
643 }
644 
FindImportFunction(const ImportVector & imports,uint32_t funcImportIndex)645 static const Import& FindImportFunction(const ImportVector& imports,
646                                         uint32_t funcImportIndex) {
647   for (const Import& import : imports) {
648     if (import.kind != DefinitionKind::Function) {
649       continue;
650     }
651     if (funcImportIndex == 0) {
652       return import;
653     }
654     funcImportIndex--;
655   }
656   MOZ_CRASH("ran out of imports");
657 }
658 
instantiateFunctions(JSContext * cx,const JSFunctionVector & funcImports) const659 bool Module::instantiateFunctions(JSContext* cx,
660                                   const JSFunctionVector& funcImports) const {
661 #ifdef DEBUG
662   for (auto t : code().tiers()) {
663     MOZ_ASSERT(funcImports.length() == metadata(t).funcImports.length());
664   }
665 #endif
666 
667   if (metadata().isAsmJS()) {
668     return true;
669   }
670 
671   Tier tier = code().stableTier();
672 
673   for (size_t i = 0; i < metadata(tier).funcImports.length(); i++) {
674     JSFunction* f = funcImports[i];
675     if (!IsWasmExportedFunction(f)) {
676       continue;
677     }
678 
679     uint32_t funcIndex = ExportedFunctionToFuncIndex(f);
680     Instance& instance = ExportedFunctionToInstance(f);
681     Tier otherTier = instance.code().stableTier();
682 
683     const FuncExport& funcExport =
684         instance.metadata(otherTier).lookupFuncExport(funcIndex);
685 
686     if (funcExport.funcType() != metadata(tier).funcImports[i].funcType()) {
687       const Import& import = FindImportFunction(imports_, i);
688       JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
689                                JSMSG_WASM_BAD_IMPORT_SIG, import.module.get(),
690                                import.field.get());
691       return false;
692     }
693   }
694 
695   return true;
696 }
697 
698 template <typename T>
CheckLimits(JSContext * cx,T declaredMin,const Maybe<T> & declaredMax,T defaultMax,T actualLength,const Maybe<T> & actualMax,bool isAsmJS,const char * kind)699 static bool CheckLimits(JSContext* cx, T declaredMin,
700                         const Maybe<T>& declaredMax, T defaultMax,
701                         T actualLength, const Maybe<T>& actualMax, bool isAsmJS,
702                         const char* kind) {
703   if (isAsmJS) {
704     MOZ_ASSERT(actualLength >= declaredMin);
705     MOZ_ASSERT(!declaredMax);
706     MOZ_ASSERT(actualLength == actualMax.value());
707     return true;
708   }
709 
710   if (actualLength < declaredMin ||
711       actualLength > declaredMax.valueOr(defaultMax)) {
712     JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
713                              JSMSG_WASM_BAD_IMP_SIZE, kind);
714     return false;
715   }
716 
717   if ((actualMax && declaredMax && *actualMax > *declaredMax) ||
718       (!actualMax && declaredMax)) {
719     JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
720                              JSMSG_WASM_BAD_IMP_MAX, kind);
721     return false;
722   }
723 
724   return true;
725 }
726 
CheckSharing(JSContext * cx,bool declaredShared,bool isShared)727 static bool CheckSharing(JSContext* cx, bool declaredShared, bool isShared) {
728   if (isShared &&
729       !cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled()) {
730     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
731                               JSMSG_WASM_NO_SHMEM_LINK);
732     return false;
733   }
734 
735   if (declaredShared && !isShared) {
736     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
737                               JSMSG_WASM_IMP_SHARED_REQD);
738     return false;
739   }
740 
741   if (!declaredShared && isShared) {
742     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
743                               JSMSG_WASM_IMP_SHARED_BANNED);
744     return false;
745   }
746 
747   return true;
748 }
749 
750 // asm.js module instantiation supplies its own buffer, but for wasm, create and
751 // initialize the buffer if one is requested. Either way, the buffer is wrapped
752 // in a WebAssembly.Memory object which is what the Instance stores.
instantiateMemory(JSContext * cx,MutableHandleWasmMemoryObject memory) const753 bool Module::instantiateMemory(JSContext* cx,
754                                MutableHandleWasmMemoryObject memory) const {
755   if (!metadata().usesMemory()) {
756     MOZ_ASSERT(!memory);
757     MOZ_ASSERT(AllSegmentsArePassive(dataSegments_));
758     return true;
759   }
760 
761   MemoryDesc desc = *metadata().memory;
762   if (memory) {
763     MOZ_ASSERT_IF(metadata().isAsmJS(), memory->buffer().isPreparedForAsmJS());
764     MOZ_ASSERT_IF(!metadata().isAsmJS(), memory->buffer().isWasm());
765 
766     if (memory->indexType() != desc.indexType()) {
767       JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
768                                JSMSG_WASM_BAD_IMP_INDEX,
769                                ToString(memory->indexType()));
770       return false;
771     }
772 
773     if (!CheckLimits(cx, desc.initialPages(), desc.maximumPages(),
774                      /* defaultMax */ MaxMemoryPages(desc.indexType()),
775                      /* actualLength */
776                      memory->volatilePages(), memory->sourceMaxPages(),
777                      metadata().isAsmJS(), "Memory")) {
778       return false;
779     }
780 
781     if (!CheckSharing(cx, desc.isShared(), memory->isShared())) {
782       return false;
783     }
784   } else {
785     MOZ_ASSERT(!metadata().isAsmJS());
786 
787     if (desc.initialPages() > MaxMemoryPages(desc.indexType())) {
788       JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
789                                JSMSG_WASM_MEM_IMP_LIMIT);
790       return false;
791     }
792 
793     RootedArrayBufferObjectMaybeShared buffer(cx);
794     if (!CreateWasmBuffer(cx, desc, &buffer)) {
795       return false;
796     }
797 
798     RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmMemory));
799     memory.set(WasmMemoryObject::create(
800         cx, buffer, IsHugeMemoryEnabled(desc.indexType()), proto));
801     if (!memory) {
802       return false;
803     }
804   }
805 
806   MOZ_RELEASE_ASSERT(memory->isHuge() == metadata().omitsBoundsChecks);
807 
808   return true;
809 }
810 
811 #ifdef ENABLE_WASM_EXCEPTIONS
instantiateTags(JSContext * cx,WasmTagObjectVector & tagObjs) const812 bool Module::instantiateTags(JSContext* cx,
813                              WasmTagObjectVector& tagObjs) const {
814   size_t tagLength = metadata().tags.length();
815   if (tagLength == 0) {
816     return true;
817   }
818   size_t importedTagsLength = tagObjs.length();
819   if (tagObjs.length() <= tagLength && !tagObjs.resize(tagLength)) {
820     ReportOutOfMemory(cx);
821     return false;
822   }
823 
824   uint32_t tagIndex = 0;
825   RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmTag));
826   for (const TagDesc& desc : metadata().tags) {
827     if (tagIndex >= importedTagsLength) {
828       RootedWasmTagObject tagObj(cx,
829                                  WasmTagObject::create(cx, desc.type, proto));
830       if (!tagObj) {
831         return false;
832       }
833       tagObjs[tagIndex] = tagObj;
834     }
835     tagIndex++;
836   }
837   return true;
838 }
839 #endif
840 
instantiateImportedTable(JSContext * cx,const TableDesc & td,Handle<WasmTableObject * > tableObj,WasmTableObjectVector * tableObjs,SharedTableVector * tables) const841 bool Module::instantiateImportedTable(JSContext* cx, const TableDesc& td,
842                                       Handle<WasmTableObject*> tableObj,
843                                       WasmTableObjectVector* tableObjs,
844                                       SharedTableVector* tables) const {
845   MOZ_ASSERT(tableObj);
846   MOZ_ASSERT(!metadata().isAsmJS());
847 
848   Table& table = tableObj->table();
849   if (!CheckLimits(cx, td.initialLength, td.maximumLength,
850                    /* declaredMin */ MaxTableLimitField,
851                    /* actualLength */ table.length(), table.maximum(),
852                    metadata().isAsmJS(), "Table")) {
853     return false;
854   }
855 
856   if (!tables->append(&table)) {
857     ReportOutOfMemory(cx);
858     return false;
859   }
860 
861   if (!tableObjs->append(tableObj)) {
862     ReportOutOfMemory(cx);
863     return false;
864   }
865 
866   return true;
867 }
868 
instantiateLocalTable(JSContext * cx,const TableDesc & td,WasmTableObjectVector * tableObjs,SharedTableVector * tables) const869 bool Module::instantiateLocalTable(JSContext* cx, const TableDesc& td,
870                                    WasmTableObjectVector* tableObjs,
871                                    SharedTableVector* tables) const {
872   if (td.initialLength > MaxTableLength) {
873     JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
874                              JSMSG_WASM_TABLE_IMP_LIMIT);
875     return false;
876   }
877 
878   SharedTable table;
879   Rooted<WasmTableObject*> tableObj(cx);
880   if (td.isImportedOrExported) {
881     RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmTable));
882     tableObj.set(WasmTableObject::create(cx, td.initialLength, td.maximumLength,
883                                          td.elemType, proto));
884     if (!tableObj) {
885       return false;
886     }
887     table = &tableObj->table();
888   } else {
889     table = Table::create(cx, td, /* HandleWasmTableObject = */ nullptr);
890     if (!table) {
891       return false;
892     }
893   }
894 
895   // Note, appending a null pointer for non-exported local tables.
896   if (!tableObjs->append(tableObj.get())) {
897     ReportOutOfMemory(cx);
898     return false;
899   }
900 
901   if (!tables->emplaceBack(table)) {
902     ReportOutOfMemory(cx);
903     return false;
904   }
905 
906   return true;
907 }
908 
instantiateTables(JSContext * cx,const WasmTableObjectVector & tableImports,MutableHandle<WasmTableObjectVector> tableObjs,SharedTableVector * tables) const909 bool Module::instantiateTables(JSContext* cx,
910                                const WasmTableObjectVector& tableImports,
911                                MutableHandle<WasmTableObjectVector> tableObjs,
912                                SharedTableVector* tables) const {
913   uint32_t tableIndex = 0;
914   for (const TableDesc& td : metadata().tables) {
915     if (tableIndex < tableImports.length()) {
916       Rooted<WasmTableObject*> tableObj(cx, tableImports[tableIndex]);
917       if (!instantiateImportedTable(cx, td, tableObj, &tableObjs.get(),
918                                     tables)) {
919         return false;
920       }
921     } else {
922       if (!instantiateLocalTable(cx, td, &tableObjs.get(), tables)) {
923         return false;
924       }
925     }
926     tableIndex++;
927   }
928   return true;
929 }
930 
EnsureExportedGlobalObject(JSContext * cx,const ValVector & globalImportValues,size_t globalIndex,const GlobalDesc & global,WasmGlobalObjectVector & globalObjs)931 static bool EnsureExportedGlobalObject(JSContext* cx,
932                                        const ValVector& globalImportValues,
933                                        size_t globalIndex,
934                                        const GlobalDesc& global,
935                                        WasmGlobalObjectVector& globalObjs) {
936   if (globalIndex < globalObjs.length() && globalObjs[globalIndex]) {
937     return true;
938   }
939 
940   RootedVal val(cx);
941   if (global.kind() == GlobalKind::Import) {
942     // If this is an import, then this must be a constant global that was
943     // provided without a global object. We must initialize it with the
944     // provided value while we still can differentiate this case.
945     MOZ_ASSERT(!global.isMutable());
946     val.set(Val(globalImportValues[globalIndex]));
947   } else {
948     // If this is not an import, then the initial value will be set by
949     // Instance::init() for indirect globals or else by CreateExportObject().
950     // In either case, we initialize with a default value here.
951     val.set(Val(global.type()));
952   }
953 
954   RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmGlobal));
955   RootedWasmGlobalObject go(
956       cx, WasmGlobalObject::create(cx, val, global.isMutable(), proto));
957   if (!go) {
958     return false;
959   }
960 
961   if (globalObjs.length() <= globalIndex &&
962       !globalObjs.resize(globalIndex + 1)) {
963     ReportOutOfMemory(cx);
964     return false;
965   }
966 
967   globalObjs[globalIndex] = go;
968   return true;
969 }
970 
instantiateGlobals(JSContext * cx,const ValVector & globalImportValues,WasmGlobalObjectVector & globalObjs) const971 bool Module::instantiateGlobals(JSContext* cx,
972                                 const ValVector& globalImportValues,
973                                 WasmGlobalObjectVector& globalObjs) const {
974   // If there are exported globals that aren't in globalObjs because they
975   // originate in this module or because they were immutable imports that came
976   // in as primitive values then we must create cells in the globalObjs for
977   // them here, as WasmInstanceObject::create() and CreateExportObject() will
978   // need the cells to exist.
979 
980   const GlobalDescVector& globals = metadata().globals;
981 
982   for (const Export& exp : exports_) {
983     if (exp.kind() != DefinitionKind::Global) {
984       continue;
985     }
986     unsigned globalIndex = exp.globalIndex();
987     const GlobalDesc& global = globals[globalIndex];
988     if (!EnsureExportedGlobalObject(cx, globalImportValues, globalIndex, global,
989                                     globalObjs)) {
990       return false;
991     }
992   }
993 
994   // Imported globals that are not re-exported may also have received only a
995   // primitive value; these globals are always immutable.  Assert that we do
996   // not need to create any additional Global objects for such imports.
997 
998 #ifdef DEBUG
999   size_t numGlobalImports = 0;
1000   for (const Import& import : imports_) {
1001     if (import.kind != DefinitionKind::Global) {
1002       continue;
1003     }
1004     size_t globalIndex = numGlobalImports++;
1005     const GlobalDesc& global = globals[globalIndex];
1006     MOZ_ASSERT(global.importIndex() == globalIndex);
1007     MOZ_ASSERT_IF(global.isIndirect(),
1008                   globalIndex < globalObjs.length() || globalObjs[globalIndex]);
1009   }
1010   MOZ_ASSERT_IF(!metadata().isAsmJS(),
1011                 numGlobalImports == globals.length() ||
1012                     !globals[numGlobalImports].isImport());
1013 #endif
1014   return true;
1015 }
1016 
getDebugEnabledCode() const1017 SharedCode Module::getDebugEnabledCode() const {
1018   MOZ_ASSERT(metadata().debugEnabled);
1019   MOZ_ASSERT(debugUnlinkedCode_);
1020   MOZ_ASSERT(debugLinkData_);
1021 
1022   // The first time through, use the pre-linked code in the module but
1023   // mark it as having been claimed. Subsequently, instantiate the copy of the
1024   // code bytes that we keep around for debugging instead, because the
1025   // debugger may patch the pre-linked code at any time.
1026   if (debugCodeClaimed_.compareExchange(false, true)) {
1027     return code_;
1028   }
1029 
1030   Tier tier = Tier::Baseline;
1031   auto segment =
1032       ModuleSegment::create(tier, *debugUnlinkedCode_, *debugLinkData_);
1033   if (!segment) {
1034     return nullptr;
1035   }
1036 
1037   UniqueMetadataTier metadataTier = js::MakeUnique<MetadataTier>(tier);
1038   if (!metadataTier || !metadataTier->clone(metadata(tier))) {
1039     return nullptr;
1040   }
1041 
1042   auto codeTier =
1043       js::MakeUnique<CodeTier>(std::move(metadataTier), std::move(segment));
1044   if (!codeTier) {
1045     return nullptr;
1046   }
1047 
1048   JumpTables jumpTables;
1049   if (!jumpTables.init(CompileMode::Once, codeTier->segment(),
1050                        metadata(tier).codeRanges)) {
1051     return nullptr;
1052   }
1053 
1054   MutableCode debugCode =
1055       js_new<Code>(std::move(codeTier), metadata(), std::move(jumpTables));
1056   if (!debugCode || !debugCode->initialize(*debugLinkData_)) {
1057     return nullptr;
1058   }
1059 
1060   return debugCode;
1061 }
1062 
GetFunctionExport(JSContext * cx,HandleWasmInstanceObject instanceObj,const JSFunctionVector & funcImports,uint32_t funcIndex,MutableHandleFunction func)1063 static bool GetFunctionExport(JSContext* cx,
1064                               HandleWasmInstanceObject instanceObj,
1065                               const JSFunctionVector& funcImports,
1066                               uint32_t funcIndex, MutableHandleFunction func) {
1067   if (funcIndex < funcImports.length() &&
1068       IsWasmExportedFunction(funcImports[funcIndex])) {
1069     func.set(funcImports[funcIndex]);
1070     return true;
1071   }
1072 
1073   return instanceObj->getExportedFunction(cx, instanceObj, funcIndex, func);
1074 }
1075 
GetGlobalExport(JSContext * cx,HandleWasmInstanceObject instanceObj,const JSFunctionVector & funcImports,const GlobalDesc & global,uint32_t globalIndex,const ValVector & globalImportValues,const WasmGlobalObjectVector & globalObjs,MutableHandleValue val)1076 static bool GetGlobalExport(JSContext* cx, HandleWasmInstanceObject instanceObj,
1077                             const JSFunctionVector& funcImports,
1078                             const GlobalDesc& global, uint32_t globalIndex,
1079                             const ValVector& globalImportValues,
1080                             const WasmGlobalObjectVector& globalObjs,
1081                             MutableHandleValue val) {
1082   // A global object for this index is guaranteed to exist by
1083   // instantiateGlobals.
1084   RootedWasmGlobalObject globalObj(cx, globalObjs[globalIndex]);
1085   val.setObject(*globalObj);
1086 
1087   // We are responsible to set the initial value of the global object here if
1088   // it's not imported or indirect. Imported global objects have their initial
1089   // value set by their defining module, or are set by
1090   // EnsureExportedGlobalObject when a constant value is provided as an import.
1091   // Indirect exported globals that are not imported, are initialized in
1092   // Instance::init.
1093   if (global.isIndirect() || global.isImport()) {
1094     return true;
1095   }
1096 
1097   // This must be an exported immutable global defined in this module. The
1098   // instance either has compiled the value into the code or has its own copy
1099   // in its global data area. Either way, we must initialize the global object
1100   // with the same initial value.
1101   MOZ_ASSERT(!global.isMutable());
1102   MOZ_ASSERT(!global.isImport());
1103   RootedVal globalVal(cx);
1104   MOZ_RELEASE_ASSERT(!global.isImport());
1105   const InitExpr& init = global.initExpr();
1106   if (!init.evaluate(cx, globalImportValues, instanceObj, &globalVal)) {
1107     return false;
1108   }
1109   globalObj->val() = globalVal;
1110   return true;
1111 }
1112 
CreateExportObject(JSContext * cx,HandleWasmInstanceObject instanceObj,const JSFunctionVector & funcImports,const WasmTableObjectVector & tableObjs,HandleWasmMemoryObject memoryObj,const WasmTagObjectVector & tagObjs,const ValVector & globalImportValues,const WasmGlobalObjectVector & globalObjs,const ExportVector & exports)1113 static bool CreateExportObject(
1114     JSContext* cx, HandleWasmInstanceObject instanceObj,
1115     const JSFunctionVector& funcImports, const WasmTableObjectVector& tableObjs,
1116     HandleWasmMemoryObject memoryObj, const WasmTagObjectVector& tagObjs,
1117     const ValVector& globalImportValues,
1118     const WasmGlobalObjectVector& globalObjs, const ExportVector& exports) {
1119   const Instance& instance = instanceObj->instance();
1120   const Metadata& metadata = instance.metadata();
1121   const GlobalDescVector& globals = metadata.globals;
1122 
1123   if (metadata.isAsmJS() && exports.length() == 1 &&
1124       strlen(exports[0].fieldName()) == 0) {
1125     RootedFunction func(cx);
1126     if (!GetFunctionExport(cx, instanceObj, funcImports, exports[0].funcIndex(),
1127                            &func)) {
1128       return false;
1129     }
1130     instanceObj->initExportsObj(*func.get());
1131     return true;
1132   }
1133 
1134   RootedObject exportObj(cx);
1135   uint8_t propertyAttr = JSPROP_ENUMERATE;
1136 
1137   if (metadata.isAsmJS()) {
1138     exportObj = NewPlainObject(cx);
1139   } else {
1140     exportObj = NewPlainObjectWithProto(cx, nullptr);
1141     propertyAttr |= JSPROP_READONLY | JSPROP_PERMANENT;
1142   }
1143   if (!exportObj) {
1144     return false;
1145   }
1146 
1147   for (const Export& exp : exports) {
1148     JSAtom* atom =
1149         AtomizeUTF8Chars(cx, exp.fieldName(), strlen(exp.fieldName()));
1150     if (!atom) {
1151       return false;
1152     }
1153 
1154     RootedId id(cx, AtomToId(atom));
1155     RootedValue val(cx);
1156     switch (exp.kind()) {
1157       case DefinitionKind::Function: {
1158         RootedFunction func(cx);
1159         if (!GetFunctionExport(cx, instanceObj, funcImports, exp.funcIndex(),
1160                                &func)) {
1161           return false;
1162         }
1163         val = ObjectValue(*func);
1164         break;
1165       }
1166       case DefinitionKind::Table: {
1167         val = ObjectValue(*tableObjs[exp.tableIndex()]);
1168         break;
1169       }
1170       case DefinitionKind::Memory: {
1171         val = ObjectValue(*memoryObj);
1172         break;
1173       }
1174       case DefinitionKind::Global: {
1175         const GlobalDesc& global = globals[exp.globalIndex()];
1176         if (!GetGlobalExport(cx, instanceObj, funcImports, global,
1177                              exp.globalIndex(), globalImportValues, globalObjs,
1178                              &val)) {
1179           return false;
1180         }
1181         break;
1182       }
1183 #ifdef ENABLE_WASM_EXCEPTIONS
1184       case DefinitionKind::Tag: {
1185         val = ObjectValue(*tagObjs[exp.tagIndex()]);
1186         break;
1187       }
1188 #endif
1189     }
1190 
1191     if (!JS_DefinePropertyById(cx, exportObj, id, val, propertyAttr)) {
1192       return false;
1193     }
1194   }
1195 
1196   if (!metadata.isAsmJS()) {
1197     if (!PreventExtensions(cx, exportObj)) {
1198       return false;
1199     }
1200   }
1201 
1202   instanceObj->initExportsObj(*exportObj);
1203   return true;
1204 }
1205 
instantiate(JSContext * cx,ImportValues & imports,HandleObject instanceProto,MutableHandleWasmInstanceObject instance) const1206 bool Module::instantiate(JSContext* cx, ImportValues& imports,
1207                          HandleObject instanceProto,
1208                          MutableHandleWasmInstanceObject instance) const {
1209   MOZ_RELEASE_ASSERT(cx->wasm().haveSignalHandlers);
1210 
1211   if (!instantiateFunctions(cx, imports.funcs)) {
1212     return false;
1213   }
1214 
1215   RootedWasmMemoryObject memory(cx, imports.memory);
1216   if (!instantiateMemory(cx, &memory)) {
1217     return false;
1218   }
1219 
1220   // Note that the following will extend imports.exceptionObjs with wrappers for
1221   // the local (non-imported) exceptions of the module.
1222   // The resulting vector is sparse, i.e., it will be null in slots that contain
1223   // exceptions that are neither exported or imported.
1224   // On the contrary, all the slots of exceptionTags will be filled with
1225   // unique tags.
1226 
1227 #ifdef ENABLE_WASM_EXCEPTIONS
1228   if (!instantiateTags(cx, imports.tagObjs)) {
1229     return false;
1230   }
1231 #endif
1232 
1233   // Note that tableObjs is sparse: it will be null in slots that contain
1234   // tables that are neither exported nor imported.
1235 
1236   Rooted<WasmTableObjectVector> tableObjs(cx);
1237   SharedTableVector tables;
1238   if (!instantiateTables(cx, imports.tables, &tableObjs, &tables)) {
1239     return false;
1240   }
1241 
1242   if (!instantiateGlobals(cx, imports.globalValues, imports.globalObjs)) {
1243     return false;
1244   }
1245 
1246   SharedCode code;
1247   UniqueDebugState maybeDebug;
1248   if (metadata().debugEnabled) {
1249     code = getDebugEnabledCode();
1250     if (!code) {
1251       ReportOutOfMemory(cx);
1252       return false;
1253     }
1254 
1255     maybeDebug = cx->make_unique<DebugState>(*code, *this);
1256     if (!maybeDebug) {
1257       ReportOutOfMemory(cx);
1258       return false;
1259     }
1260   } else {
1261     code = code_;
1262   }
1263 
1264   instance.set(WasmInstanceObject::create(
1265       cx, code, dataSegments_, elemSegments_, metadata().globalDataLength,
1266       memory, std::move(tables), imports.funcs, metadata().globals,
1267       imports.globalValues, imports.globalObjs, imports.tagObjs, instanceProto,
1268       std::move(maybeDebug)));
1269   if (!instance) {
1270     return false;
1271   }
1272 
1273   if (!CreateExportObject(cx, instance, imports.funcs, tableObjs.get(), memory,
1274                           imports.tagObjs, imports.globalValues,
1275                           imports.globalObjs, exports_)) {
1276     return false;
1277   }
1278 
1279   // Register the instance with the Realm so that it can find out about global
1280   // events like profiling being enabled in the realm. Registration does not
1281   // require a fully-initialized instance and must precede initSegments as the
1282   // final pre-requisite for a live instance.
1283 
1284   if (!cx->realm()->wasm.registerInstance(cx, instance)) {
1285     ReportOutOfMemory(cx);
1286     return false;
1287   }
1288 
1289   // Perform initialization as the final step after the instance is fully
1290   // constructed since this can make the instance live to content (even if the
1291   // start function fails).
1292 
1293   if (!initSegments(cx, instance, memory, imports.globalValues)) {
1294     return false;
1295   }
1296 
1297   // Now that the instance is fully live and initialized, the start function.
1298   // Note that failure may cause instantiation to throw, but the instance may
1299   // still be live via edges created by initSegments or the start function.
1300 
1301   if (metadata().startFuncIndex) {
1302     FixedInvokeArgs<0> args(cx);
1303     if (!instance->instance().callExport(cx, *metadata().startFuncIndex,
1304                                          args)) {
1305       return false;
1306     }
1307   }
1308 
1309   JSUseCounter useCounter =
1310       metadata().isAsmJS() ? JSUseCounter::ASMJS : JSUseCounter::WASM;
1311   cx->runtime()->setUseCounter(instance, useCounter);
1312 
1313   if (cx->options().testWasmAwaitTier2()) {
1314     testingBlockOnTier2Complete();
1315   }
1316 
1317   return true;
1318 }
1319