LCOV - code coverage report
Current view: top level - js/src/wasm - WasmInstance.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 5 464 1.1 %
Date: 2017-07-14 16:53:18 Functions: 2 40 5.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  *
       4             :  * Copyright 2016 Mozilla Foundation
       5             :  *
       6             :  * Licensed under the Apache License, Version 2.0 (the "License");
       7             :  * you may not use this file except in compliance with the License.
       8             :  * You may obtain a copy of the License at
       9             :  *
      10             :  *     http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  * Unless required by applicable law or agreed to in writing, software
      13             :  * distributed under the License is distributed on an "AS IS" BASIS,
      14             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  * See the License for the specific language governing permissions and
      16             :  * limitations under the License.
      17             :  */
      18             : 
      19             : #include "wasm/WasmInstance.h"
      20             : 
      21             : #include "jit/BaselineJIT.h"
      22             : #include "jit/InlinableNatives.h"
      23             : #include "jit/JitCommon.h"
      24             : #include "wasm/WasmBuiltins.h"
      25             : #include "wasm/WasmModule.h"
      26             : 
      27             : #include "jsobjinlines.h"
      28             : 
      29             : #include "vm/ArrayBufferObject-inl.h"
      30             : 
      31             : using namespace js;
      32             : using namespace js::jit;
      33             : using namespace js::wasm;
      34             : using mozilla::BinarySearch;
      35             : using mozilla::BitwiseCast;
      36             : using mozilla::IsNaN;
      37             : using mozilla::Swap;
      38             : 
      39           3 : class SigIdSet
      40             : {
      41             :     typedef HashMap<const Sig*, uint32_t, SigHashPolicy, SystemAllocPolicy> Map;
      42             :     Map map_;
      43             : 
      44             :   public:
      45           0 :     ~SigIdSet() {
      46           0 :         MOZ_ASSERT_IF(!JSRuntime::hasLiveRuntimes(), !map_.initialized() || map_.empty());
      47           0 :     }
      48             : 
      49           0 :     bool ensureInitialized(JSContext* cx) {
      50           0 :         if (!map_.initialized() && !map_.init()) {
      51           0 :             ReportOutOfMemory(cx);
      52           0 :             return false;
      53             :         }
      54             : 
      55           0 :         return true;
      56             :     }
      57             : 
      58           0 :     bool allocateSigId(JSContext* cx, const Sig& sig, const void** sigId) {
      59           0 :         Map::AddPtr p = map_.lookupForAdd(sig);
      60           0 :         if (p) {
      61           0 :             MOZ_ASSERT(p->value() > 0);
      62           0 :             p->value()++;
      63           0 :             *sigId = p->key();
      64           0 :             return true;
      65             :         }
      66             : 
      67           0 :         UniquePtr<Sig> clone = MakeUnique<Sig>();
      68           0 :         if (!clone || !clone->clone(sig) || !map_.add(p, clone.get(), 1)) {
      69           0 :             ReportOutOfMemory(cx);
      70           0 :             return false;
      71             :         }
      72             : 
      73           0 :         *sigId = clone.release();
      74           0 :         MOZ_ASSERT(!(uintptr_t(*sigId) & SigIdDesc::ImmediateBit));
      75           0 :         return true;
      76             :     }
      77             : 
      78           0 :     void deallocateSigId(const Sig& sig, const void* sigId) {
      79           0 :         Map::Ptr p = map_.lookup(sig);
      80           0 :         MOZ_RELEASE_ASSERT(p && p->key() == sigId && p->value() > 0);
      81             : 
      82           0 :         p->value()--;
      83           0 :         if (!p->value()) {
      84           0 :             js_delete(p->key());
      85           0 :             map_.remove(p);
      86             :         }
      87           0 :     }
      88             : };
      89             : 
      90             : ExclusiveData<SigIdSet>* sigIdSet = nullptr;
      91             : 
      92             : bool
      93           3 : js::wasm::InitInstanceStaticData()
      94             : {
      95           3 :     MOZ_ASSERT(!sigIdSet);
      96           3 :     sigIdSet = js_new<ExclusiveData<SigIdSet>>(mutexid::WasmSigIdSet);
      97           3 :     return sigIdSet != nullptr;
      98             : }
      99             : 
     100             : void
     101           0 : js::wasm::ShutDownInstanceStaticData()
     102             : {
     103           0 :     MOZ_ASSERT(sigIdSet);
     104           0 :     js_delete(sigIdSet);
     105           0 :     sigIdSet = nullptr;
     106           0 : }
     107             : 
     108             : const void**
     109           0 : Instance::addressOfSigId(const SigIdDesc& sigId) const
     110             : {
     111           0 :     return (const void**)(globalSegment().globalData() + sigId.globalDataOffset());
     112             : }
     113             : 
     114             : FuncImportTls&
     115           0 : Instance::funcImportTls(const FuncImport& fi)
     116             : {
     117           0 :     return *(FuncImportTls*)(globalSegment().globalData() + fi.tlsDataOffset());
     118             : }
     119             : 
     120             : TableTls&
     121           0 : Instance::tableTls(const TableDesc& td) const
     122             : {
     123           0 :     return *(TableTls*)(globalSegment().globalData() + td.globalDataOffset);
     124             : }
     125             : 
     126             : bool
     127           0 : Instance::callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, const uint64_t* argv,
     128             :                      MutableHandleValue rval)
     129             : {
     130           0 :     Tier tier = Tier::TBD;
     131             : 
     132           0 :     const FuncImport& fi = metadata(tier).funcImports[funcImportIndex];
     133             : 
     134           0 :     InvokeArgs args(cx);
     135           0 :     if (!args.init(cx, argc))
     136           0 :         return false;
     137             : 
     138           0 :     bool hasI64Arg = false;
     139           0 :     MOZ_ASSERT(fi.sig().args().length() == argc);
     140           0 :     for (size_t i = 0; i < argc; i++) {
     141           0 :         switch (fi.sig().args()[i]) {
     142             :           case ValType::I32:
     143           0 :             args[i].set(Int32Value(*(int32_t*)&argv[i]));
     144           0 :             break;
     145             :           case ValType::F32:
     146           0 :             args[i].set(JS::CanonicalizedDoubleValue(*(float*)&argv[i]));
     147           0 :             break;
     148             :           case ValType::F64:
     149           0 :             args[i].set(JS::CanonicalizedDoubleValue(*(double*)&argv[i]));
     150           0 :             break;
     151             :           case ValType::I64: {
     152           0 :             if (!JitOptions.wasmTestMode) {
     153           0 :                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_I64);
     154           0 :                 return false;
     155             :             }
     156           0 :             RootedObject obj(cx, CreateI64Object(cx, *(int64_t*)&argv[i]));
     157           0 :             if (!obj)
     158           0 :                 return false;
     159           0 :             args[i].set(ObjectValue(*obj));
     160           0 :             hasI64Arg = true;
     161           0 :             break;
     162             :           }
     163             :           case ValType::I8x16:
     164             :           case ValType::I16x8:
     165             :           case ValType::I32x4:
     166             :           case ValType::F32x4:
     167             :           case ValType::B8x16:
     168             :           case ValType::B16x8:
     169             :           case ValType::B32x4:
     170           0 :             MOZ_CRASH("unhandled type in callImport");
     171             :         }
     172             :     }
     173             : 
     174           0 :     FuncImportTls& import = funcImportTls(fi);
     175           0 :     RootedFunction importFun(cx, &import.obj->as<JSFunction>());
     176           0 :     RootedValue fval(cx, ObjectValue(*import.obj));
     177           0 :     RootedValue thisv(cx, UndefinedValue());
     178           0 :     if (!Call(cx, fval, thisv, args, rval))
     179           0 :         return false;
     180             : 
     181             :     // Throw an error if returning i64 and not in test mode.
     182           0 :     if (!JitOptions.wasmTestMode && fi.sig().ret() == ExprType::I64) {
     183           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_I64);
     184           0 :         return false;
     185             :     }
     186             : 
     187             :     // Don't try to optimize if the function has at least one i64 arg or if
     188             :     // it returns an int64. GenerateJitExit relies on this, as does the
     189             :     // type inference code below in this function.
     190           0 :     if (hasI64Arg || fi.sig().ret() == ExprType::I64)
     191           0 :         return true;
     192             : 
     193             :     // The import may already have become optimized.
     194           0 :     void* jitExitCode = codeBase(tier) + fi.jitExitCodeOffset();
     195           0 :     if (import.code == jitExitCode)
     196           0 :         return true;
     197             : 
     198             :     // Test if the function is JIT compiled.
     199           0 :     if (!importFun->hasScript())
     200           0 :         return true;
     201             : 
     202           0 :     JSScript* script = importFun->nonLazyScript();
     203           0 :     if (!script->hasBaselineScript()) {
     204           0 :         MOZ_ASSERT(!script->hasIonScript());
     205           0 :         return true;
     206             :     }
     207             : 
     208             :     // Don't enable jit entry when we have a pending ion builder.
     209             :     // Take the interpreter path which will link it and enable
     210             :     // the fast path on the next call.
     211           0 :     if (script->baselineScript()->hasPendingIonBuilder())
     212           0 :         return true;
     213             : 
     214             :     // Currently we can't rectify arguments. Therefore disable if argc is too low.
     215           0 :     if (importFun->nargs() > fi.sig().args().length())
     216           0 :         return true;
     217             : 
     218             :     // Ensure the argument types are included in the argument TypeSets stored in
     219             :     // the TypeScript. This is necessary for Ion, because the import will use
     220             :     // the skip-arg-checks entry point.
     221             :     //
     222             :     // Note that the TypeScript is never discarded while the script has a
     223             :     // BaselineScript, so if those checks hold now they must hold at least until
     224             :     // the BaselineScript is discarded and when that happens the import is
     225             :     // patched back.
     226           0 :     if (!TypeScript::ThisTypes(script)->hasType(TypeSet::UndefinedType()))
     227           0 :         return true;
     228           0 :     for (uint32_t i = 0; i < importFun->nargs(); i++) {
     229           0 :         TypeSet::Type type = TypeSet::UnknownType();
     230           0 :         switch (fi.sig().args()[i]) {
     231           0 :           case ValType::I32:   type = TypeSet::Int32Type(); break;
     232           0 :           case ValType::I64:   MOZ_CRASH("can't happen because of above guard");
     233           0 :           case ValType::F32:   type = TypeSet::DoubleType(); break;
     234           0 :           case ValType::F64:   type = TypeSet::DoubleType(); break;
     235           0 :           case ValType::I8x16: MOZ_CRASH("NYI");
     236           0 :           case ValType::I16x8: MOZ_CRASH("NYI");
     237           0 :           case ValType::I32x4: MOZ_CRASH("NYI");
     238           0 :           case ValType::F32x4: MOZ_CRASH("NYI");
     239           0 :           case ValType::B8x16: MOZ_CRASH("NYI");
     240           0 :           case ValType::B16x8: MOZ_CRASH("NYI");
     241           0 :           case ValType::B32x4: MOZ_CRASH("NYI");
     242             :         }
     243           0 :         if (!TypeScript::ArgTypes(script, i)->hasType(type))
     244           0 :             return true;
     245             :     }
     246             : 
     247             :     // Let's optimize it!
     248           0 :     if (!script->baselineScript()->addDependentWasmImport(cx, *this, funcImportIndex))
     249           0 :         return false;
     250             : 
     251           0 :     import.code = jitExitCode;
     252           0 :     import.baselineScript = script->baselineScript();
     253           0 :     return true;
     254             : }
     255             : 
     256             : /* static */ int32_t
     257           0 : Instance::callImport_void(Instance* instance, int32_t funcImportIndex, int32_t argc, uint64_t* argv)
     258             : {
     259           0 :     JSContext* cx = TlsContext.get();
     260           0 :     RootedValue rval(cx);
     261           0 :     return instance->callImport(cx, funcImportIndex, argc, argv, &rval);
     262             : }
     263             : 
     264             : /* static */ int32_t
     265           0 : Instance::callImport_i32(Instance* instance, int32_t funcImportIndex, int32_t argc, uint64_t* argv)
     266             : {
     267           0 :     JSContext* cx = TlsContext.get();
     268           0 :     RootedValue rval(cx);
     269           0 :     if (!instance->callImport(cx, funcImportIndex, argc, argv, &rval))
     270           0 :         return false;
     271             : 
     272           0 :     return ToInt32(cx, rval, (int32_t*)argv);
     273             : }
     274             : 
     275             : /* static */ int32_t
     276           0 : Instance::callImport_i64(Instance* instance, int32_t funcImportIndex, int32_t argc, uint64_t* argv)
     277             : {
     278           0 :     JSContext* cx = TlsContext.get();
     279           0 :     RootedValue rval(cx);
     280           0 :     if (!instance->callImport(cx, funcImportIndex, argc, argv, &rval))
     281           0 :         return false;
     282             : 
     283           0 :     return ReadI64Object(cx, rval, (int64_t*)argv);
     284             : }
     285             : 
     286             : /* static */ int32_t
     287           0 : Instance::callImport_f64(Instance* instance, int32_t funcImportIndex, int32_t argc, uint64_t* argv)
     288             : {
     289           0 :     JSContext* cx = TlsContext.get();
     290           0 :     RootedValue rval(cx);
     291           0 :     if (!instance->callImport(cx, funcImportIndex, argc, argv, &rval))
     292           0 :         return false;
     293             : 
     294           0 :     return ToNumber(cx, rval, (double*)argv);
     295             : }
     296             : 
     297             : /* static */ uint32_t
     298           0 : Instance::growMemory_i32(Instance* instance, uint32_t delta)
     299             : {
     300           0 :     MOZ_ASSERT(!instance->isAsmJS());
     301             : 
     302           0 :     JSContext* cx = TlsContext.get();
     303           0 :     RootedWasmMemoryObject memory(cx, instance->memory_);
     304             : 
     305           0 :     uint32_t ret = WasmMemoryObject::grow(memory, delta, cx);
     306             : 
     307             :     // If there has been a moving grow, this Instance should have been notified.
     308           0 :     MOZ_RELEASE_ASSERT(instance->tlsData()->memoryBase ==
     309             :                        instance->memory_->buffer().dataPointerEither());
     310             : 
     311           0 :     return ret;
     312             : }
     313             : 
     314             : /* static */ uint32_t
     315           0 : Instance::currentMemory_i32(Instance* instance)
     316             : {
     317           0 :     uint32_t byteLength = instance->memoryLength();
     318           0 :     MOZ_ASSERT(byteLength % wasm::PageSize == 0);
     319           0 :     return byteLength / wasm::PageSize;
     320             : }
     321             : 
     322           0 : Instance::Instance(JSContext* cx,
     323             :                    Handle<WasmInstanceObject*> object,
     324             :                    SharedCode code,
     325             :                    UniqueDebugState debug,
     326             :                    UniqueGlobalSegment globals,
     327             :                    HandleWasmMemoryObject memory,
     328             :                    SharedTableVector&& tables,
     329             :                    Handle<FunctionVector> funcImports,
     330           0 :                    const ValVector& globalImports)
     331           0 :   : compartment_(cx->compartment()),
     332             :     object_(object),
     333             :     code_(code),
     334           0 :     debug_(Move(debug)),
     335           0 :     globals_(Move(globals)),
     336             :     memory_(memory),
     337           0 :     tables_(Move(tables)),
     338           0 :     enterFrameTrapsEnabled_(false)
     339             : {
     340             : #ifdef DEBUG
     341           0 :     for (auto t : metadata().tiers())
     342           0 :         MOZ_ASSERT(funcImports.length() == metadata(t).funcImports.length());
     343             : #endif
     344           0 :     MOZ_ASSERT(tables_.length() == metadata().tables.length());
     345             : 
     346           0 :     tlsData()->memoryBase = memory ? memory->buffer().dataPointerEither().unwrap() : nullptr;
     347             : #ifndef WASM_HUGE_MEMORY
     348             :     tlsData()->boundsCheckLimit = memory ? memory->buffer().wasmBoundsCheckLimit() : 0;
     349             : #endif
     350           0 :     tlsData()->instance = this;
     351           0 :     tlsData()->addressOfContext = (JSContext**)object->zone()->group()->addressOfOwnerContext();
     352             : 
     353           0 :     Tier callerTier = Tier::TBD;
     354           0 :     Tier calleeTier = Tier::TBD;
     355             : 
     356           0 :     for (size_t i = 0; i < metadata(callerTier).funcImports.length(); i++) {
     357           0 :         HandleFunction f = funcImports[i];
     358           0 :         const FuncImport& fi = metadata(callerTier).funcImports[i];
     359           0 :         FuncImportTls& import = funcImportTls(fi);
     360           0 :         if (!isAsmJS() && IsExportedWasmFunction(f)) {
     361           0 :             WasmInstanceObject* calleeInstanceObj = ExportedFunctionToInstanceObject(f);
     362           0 :             const CodeRange& codeRange = calleeInstanceObj->getExportedFunctionCodeRange(f, calleeTier);
     363           0 :             Instance& calleeInstance = calleeInstanceObj->instance();
     364           0 :             import.tls = calleeInstance.tlsData();
     365           0 :             import.code = calleeInstance.codeBase(calleeTier) + codeRange.funcNormalEntry();
     366           0 :             import.baselineScript = nullptr;
     367           0 :             import.obj = calleeInstanceObj;
     368           0 :         } else if (void* thunk = MaybeGetBuiltinThunk(f, fi.sig(), cx)) {
     369           0 :             import.tls = tlsData();
     370           0 :             import.code = thunk;
     371           0 :             import.baselineScript = nullptr;
     372           0 :             import.obj = f;
     373             :         } else {
     374           0 :             import.tls = tlsData();
     375           0 :             import.code = codeBase(callerTier) + fi.interpExitCodeOffset();
     376           0 :             import.baselineScript = nullptr;
     377           0 :             import.obj = f;
     378             :         }
     379             :     }
     380             : 
     381           0 :     for (size_t i = 0; i < tables_.length(); i++) {
     382           0 :         const TableDesc& td = metadata().tables[i];
     383           0 :         TableTls& table = tableTls(td);
     384           0 :         table.length = tables_[i]->length();
     385           0 :         table.base = tables_[i]->base();
     386             :     }
     387             : 
     388           0 :     uint8_t* globalData = globals_->globalData();
     389             : 
     390           0 :     for (size_t i = 0; i < metadata().globals.length(); i++) {
     391           0 :         const GlobalDesc& global = metadata().globals[i];
     392           0 :         if (global.isConstant())
     393           0 :             continue;
     394             : 
     395           0 :         uint8_t* globalAddr = globalData + global.offset();
     396           0 :         switch (global.kind()) {
     397             :           case GlobalKind::Import: {
     398           0 :             globalImports[global.importIndex()].writePayload(globalAddr);
     399           0 :             break;
     400             :           }
     401             :           case GlobalKind::Variable: {
     402           0 :             const InitExpr& init = global.initExpr();
     403           0 :             switch (init.kind()) {
     404             :               case InitExpr::Kind::Constant: {
     405           0 :                 init.val().writePayload(globalAddr);
     406           0 :                 break;
     407             :               }
     408             :               case InitExpr::Kind::GetGlobal: {
     409           0 :                 const GlobalDesc& imported = metadata().globals[init.globalIndex()];
     410           0 :                 globalImports[imported.importIndex()].writePayload(globalAddr);
     411           0 :                 break;
     412             :               }
     413             :             }
     414           0 :             break;
     415             :           }
     416             :           case GlobalKind::Constant: {
     417           0 :             MOZ_CRASH("skipped at the top");
     418             :           }
     419             :         }
     420             :     }
     421           0 : }
     422             : 
     423             : bool
     424           0 : Instance::init(JSContext* cx)
     425             : {
     426           0 :     if (memory_ && memory_->movingGrowable() && !memory_->addMovingGrowObserver(cx, object_))
     427           0 :         return false;
     428             : 
     429           0 :     for (const SharedTable& table : tables_) {
     430           0 :         if (table->movingGrowable() && !table->addMovingGrowObserver(cx, object_))
     431           0 :             return false;
     432             :     }
     433             : 
     434           0 :     if (!metadata().sigIds.empty()) {
     435           0 :         ExclusiveData<SigIdSet>::Guard lockedSigIdSet = sigIdSet->lock();
     436             : 
     437           0 :         if (!lockedSigIdSet->ensureInitialized(cx))
     438           0 :             return false;
     439             : 
     440           0 :         for (const SigWithId& sig : metadata().sigIds) {
     441             :             const void* sigId;
     442           0 :             if (!lockedSigIdSet->allocateSigId(cx, sig, &sigId))
     443           0 :                 return false;
     444             : 
     445           0 :             *addressOfSigId(sig.id) = sigId;
     446             :         }
     447             :     }
     448             : 
     449           0 :     return true;
     450             : }
     451             : 
     452           0 : Instance::~Instance()
     453             : {
     454           0 :     compartment_->wasm.unregisterInstance(*this);
     455             : 
     456           0 :     const FuncImportVector& funcImports = metadata(code().anyTier()).funcImports;
     457             : 
     458           0 :     for (unsigned i = 0; i < funcImports.length(); i++) {
     459           0 :         FuncImportTls& import = funcImportTls(funcImports[i]);
     460           0 :         if (import.baselineScript)
     461           0 :             import.baselineScript->removeDependentWasmImport(*this, i);
     462             :     }
     463             : 
     464           0 :     if (!metadata().sigIds.empty()) {
     465           0 :         ExclusiveData<SigIdSet>::Guard lockedSigIdSet = sigIdSet->lock();
     466             : 
     467           0 :         for (const SigWithId& sig : metadata().sigIds) {
     468           0 :             if (const void* sigId = *addressOfSigId(sig.id))
     469           0 :                 lockedSigIdSet->deallocateSigId(sig, sigId);
     470             :         }
     471             :     }
     472           0 : }
     473             : 
     474             : size_t
     475           0 : Instance::memoryMappedSize() const
     476             : {
     477           0 :     return memory_->buffer().wasmMappedSize();
     478             : }
     479             : 
     480             : bool
     481           0 : Instance::memoryAccessInGuardRegion(uint8_t* addr, unsigned numBytes) const
     482             : {
     483           0 :     MOZ_ASSERT(numBytes > 0);
     484             : 
     485           0 :     if (!metadata().usesMemory())
     486           0 :         return false;
     487             : 
     488           0 :     uint8_t* base = memoryBase().unwrap(/* comparison */);
     489           0 :     if (addr < base)
     490           0 :         return false;
     491             : 
     492           0 :     size_t lastByteOffset = addr - base + (numBytes - 1);
     493           0 :     return lastByteOffset >= memoryLength() && lastByteOffset < memoryMappedSize();
     494             : }
     495             : 
     496             : void
     497           0 : Instance::tracePrivate(JSTracer* trc)
     498             : {
     499             :     // This method is only called from WasmInstanceObject so the only reason why
     500             :     // TraceEdge is called is so that the pointer can be updated during a moving
     501             :     // GC. TraceWeakEdge may sound better, but it is less efficient given that
     502             :     // we know object_ is already marked.
     503           0 :     MOZ_ASSERT(!gc::IsAboutToBeFinalized(&object_));
     504           0 :     TraceEdge(trc, &object_, "wasm instance object");
     505             : 
     506           0 :     for (const FuncImport& fi : metadata(code().anyTier()).funcImports)
     507           0 :         TraceNullableEdge(trc, &funcImportTls(fi).obj, "wasm import");
     508             : 
     509           0 :     for (const SharedTable& table : tables_)
     510           0 :         table->trace(trc);
     511             : 
     512           0 :     TraceNullableEdge(trc, &memory_, "wasm buffer");
     513           0 : }
     514             : 
     515             : void
     516           0 : Instance::trace(JSTracer* trc)
     517             : {
     518             :     // Technically, instead of having this method, the caller could use
     519             :     // Instance::object() to get the owning WasmInstanceObject to mark,
     520             :     // but this method is simpler and more efficient. The trace hook of
     521             :     // WasmInstanceObject will call Instance::tracePrivate at which point we
     522             :     // can mark the rest of the children.
     523           0 :     TraceEdge(trc, &object_, "wasm instance object");
     524           0 : }
     525             : 
     526             : SharedMem<uint8_t*>
     527           0 : Instance::memoryBase() const
     528             : {
     529           0 :     MOZ_ASSERT(metadata().usesMemory());
     530           0 :     MOZ_ASSERT(tlsData()->memoryBase == memory_->buffer().dataPointerEither());
     531           0 :     return memory_->buffer().dataPointerEither();
     532             : }
     533             : 
     534             : size_t
     535           0 : Instance::memoryLength() const
     536             : {
     537           0 :     return memory_->buffer().byteLength();
     538             : }
     539             : 
     540             : WasmInstanceObject*
     541           0 : Instance::objectUnbarriered() const
     542             : {
     543           0 :     return object_.unbarrieredGet();
     544             : }
     545             : 
     546             : WasmInstanceObject*
     547           0 : Instance::object() const
     548             : {
     549           0 :     return object_;
     550             : }
     551             : 
     552             : bool
     553           0 : Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args)
     554             : {
     555             :     // If there has been a moving grow, this Instance should have been notified.
     556           0 :     MOZ_RELEASE_ASSERT(!memory_ || tlsData()->memoryBase == memory_->buffer().dataPointerEither());
     557             : 
     558           0 :     Tier tier = Tier::TBD;
     559             : 
     560           0 :     const FuncExport& func = metadata(tier).lookupFuncExport(funcIndex);
     561             : 
     562             :     // The calling convention for an external call into wasm is to pass an
     563             :     // array of 16-byte values where each value contains either a coerced int32
     564             :     // (in the low word), a double value (in the low dword) or a SIMD vector
     565             :     // value, with the coercions specified by the wasm signature. The external
     566             :     // entry point unpacks this array into the system-ABI-specified registers
     567             :     // and stack memory and then calls into the internal entry point. The return
     568             :     // value is stored in the first element of the array (which, therefore, must
     569             :     // have length >= 1).
     570           0 :     Vector<ExportArg, 8> exportArgs(cx);
     571           0 :     if (!exportArgs.resize(Max<size_t>(1, func.sig().args().length())))
     572           0 :         return false;
     573             : 
     574           0 :     RootedValue v(cx);
     575           0 :     for (unsigned i = 0; i < func.sig().args().length(); ++i) {
     576           0 :         v = i < args.length() ? args[i] : UndefinedValue();
     577           0 :         switch (func.sig().arg(i)) {
     578             :           case ValType::I32:
     579           0 :             if (!ToInt32(cx, v, (int32_t*)&exportArgs[i]))
     580           0 :                 return false;
     581           0 :             break;
     582             :           case ValType::I64:
     583           0 :             if (!JitOptions.wasmTestMode) {
     584           0 :                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_I64);
     585           0 :                 return false;
     586             :             }
     587           0 :             if (!ReadI64Object(cx, v, (int64_t*)&exportArgs[i]))
     588           0 :                 return false;
     589           0 :             break;
     590             :           case ValType::F32:
     591           0 :             if (JitOptions.wasmTestMode && v.isObject()) {
     592           0 :                 if (!ReadCustomFloat32NaNObject(cx, v, (uint32_t*)&exportArgs[i]))
     593           0 :                     return false;
     594           0 :                 break;
     595             :             }
     596           0 :             if (!RoundFloat32(cx, v, (float*)&exportArgs[i]))
     597           0 :                 return false;
     598           0 :             break;
     599             :           case ValType::F64:
     600           0 :             if (JitOptions.wasmTestMode && v.isObject()) {
     601           0 :                 if (!ReadCustomDoubleNaNObject(cx, v, (uint64_t*)&exportArgs[i]))
     602           0 :                     return false;
     603           0 :                 break;
     604             :             }
     605           0 :             if (!ToNumber(cx, v, (double*)&exportArgs[i]))
     606           0 :                 return false;
     607           0 :             break;
     608             :           case ValType::I8x16: {
     609             :             SimdConstant simd;
     610           0 :             if (!ToSimdConstant<Int8x16>(cx, v, &simd))
     611           0 :                 return false;
     612           0 :             memcpy(&exportArgs[i], simd.asInt8x16(), Simd128DataSize);
     613           0 :             break;
     614             :           }
     615             :           case ValType::I16x8: {
     616             :             SimdConstant simd;
     617           0 :             if (!ToSimdConstant<Int16x8>(cx, v, &simd))
     618           0 :                 return false;
     619           0 :             memcpy(&exportArgs[i], simd.asInt16x8(), Simd128DataSize);
     620           0 :             break;
     621             :           }
     622             :           case ValType::I32x4: {
     623             :             SimdConstant simd;
     624           0 :             if (!ToSimdConstant<Int32x4>(cx, v, &simd))
     625           0 :                 return false;
     626           0 :             memcpy(&exportArgs[i], simd.asInt32x4(), Simd128DataSize);
     627           0 :             break;
     628             :           }
     629             :           case ValType::F32x4: {
     630             :             SimdConstant simd;
     631           0 :             if (!ToSimdConstant<Float32x4>(cx, v, &simd))
     632           0 :                 return false;
     633           0 :             memcpy(&exportArgs[i], simd.asFloat32x4(), Simd128DataSize);
     634           0 :             break;
     635             :           }
     636             :           case ValType::B8x16: {
     637             :             SimdConstant simd;
     638           0 :             if (!ToSimdConstant<Bool8x16>(cx, v, &simd))
     639           0 :                 return false;
     640             :             // Bool8x16 uses the same representation as Int8x16.
     641           0 :             memcpy(&exportArgs[i], simd.asInt8x16(), Simd128DataSize);
     642           0 :             break;
     643             :           }
     644             :           case ValType::B16x8: {
     645             :             SimdConstant simd;
     646           0 :             if (!ToSimdConstant<Bool16x8>(cx, v, &simd))
     647           0 :                 return false;
     648             :             // Bool16x8 uses the same representation as Int16x8.
     649           0 :             memcpy(&exportArgs[i], simd.asInt16x8(), Simd128DataSize);
     650           0 :             break;
     651             :           }
     652             :           case ValType::B32x4: {
     653             :             SimdConstant simd;
     654           0 :             if (!ToSimdConstant<Bool32x4>(cx, v, &simd))
     655           0 :                 return false;
     656             :             // Bool32x4 uses the same representation as Int32x4.
     657           0 :             memcpy(&exportArgs[i], simd.asInt32x4(), Simd128DataSize);
     658           0 :             break;
     659             :           }
     660             :         }
     661             :     }
     662             : 
     663             :     {
     664             :         // Push a WasmActivation to describe the wasm frames we're about to push
     665             :         // when running this module. Additionally, push a JitActivation so that
     666             :         // the optimized wasm-to-Ion FFI call path (which we want to be very
     667             :         // fast) can avoid doing so. The JitActivation is marked as inactive so
     668             :         // stack iteration will skip over it.
     669           0 :         WasmActivation activation(cx);
     670           0 :         JitActivation jitActivation(cx, /* active */ false);
     671             : 
     672             :         // Call the per-exported-function trampoline created by GenerateEntry.
     673           0 :         auto funcPtr = JS_DATA_TO_FUNC_PTR(ExportFuncPtr, codeBase(tier) + func.entryOffset());
     674           0 :         if (!CALL_GENERATED_2(funcPtr, exportArgs.begin(), tlsData()))
     675           0 :             return false;
     676             :     }
     677             : 
     678           0 :     if (isAsmJS() && args.isConstructing()) {
     679             :         // By spec, when a JS function is called as a constructor and this
     680             :         // function returns a primary type, which is the case for all asm.js
     681             :         // exported functions, the returned value is discarded and an empty
     682             :         // object is returned instead.
     683           0 :         PlainObject* obj = NewBuiltinClassInstance<PlainObject>(cx);
     684           0 :         if (!obj)
     685           0 :             return false;
     686           0 :         args.rval().set(ObjectValue(*obj));
     687           0 :         return true;
     688             :     }
     689             : 
     690           0 :     void* retAddr = &exportArgs[0];
     691           0 :     JSObject* retObj = nullptr;
     692           0 :     switch (func.sig().ret()) {
     693             :       case ExprType::Void:
     694           0 :         args.rval().set(UndefinedValue());
     695           0 :         break;
     696             :       case ExprType::I32:
     697           0 :         args.rval().set(Int32Value(*(int32_t*)retAddr));
     698           0 :         break;
     699             :       case ExprType::I64:
     700           0 :         if (!JitOptions.wasmTestMode) {
     701           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_I64);
     702           0 :             return false;
     703             :         }
     704           0 :         retObj = CreateI64Object(cx, *(int64_t*)retAddr);
     705           0 :         if (!retObj)
     706           0 :             return false;
     707           0 :         break;
     708             :       case ExprType::F32:
     709           0 :         if (JitOptions.wasmTestMode && IsNaN(*(float*)retAddr)) {
     710           0 :             retObj = CreateCustomNaNObject(cx, (float*)retAddr);
     711           0 :             if (!retObj)
     712           0 :                 return false;
     713           0 :             break;
     714             :         }
     715           0 :         args.rval().set(NumberValue(*(float*)retAddr));
     716           0 :         break;
     717             :       case ExprType::F64:
     718           0 :         if (JitOptions.wasmTestMode && IsNaN(*(double*)retAddr)) {
     719           0 :             retObj = CreateCustomNaNObject(cx, (double*)retAddr);
     720           0 :             if (!retObj)
     721           0 :                 return false;
     722           0 :             break;
     723             :         }
     724           0 :         args.rval().set(NumberValue(*(double*)retAddr));
     725           0 :         break;
     726             :       case ExprType::I8x16:
     727           0 :         retObj = CreateSimd<Int8x16>(cx, (int8_t*)retAddr);
     728           0 :         if (!retObj)
     729           0 :             return false;
     730           0 :         break;
     731             :       case ExprType::I16x8:
     732           0 :         retObj = CreateSimd<Int16x8>(cx, (int16_t*)retAddr);
     733           0 :         if (!retObj)
     734           0 :             return false;
     735           0 :         break;
     736             :       case ExprType::I32x4:
     737           0 :         retObj = CreateSimd<Int32x4>(cx, (int32_t*)retAddr);
     738           0 :         if (!retObj)
     739           0 :             return false;
     740           0 :         break;
     741             :       case ExprType::F32x4:
     742           0 :         retObj = CreateSimd<Float32x4>(cx, (float*)retAddr);
     743           0 :         if (!retObj)
     744           0 :             return false;
     745           0 :         break;
     746             :       case ExprType::B8x16:
     747           0 :         retObj = CreateSimd<Bool8x16>(cx, (int8_t*)retAddr);
     748           0 :         if (!retObj)
     749           0 :             return false;
     750           0 :         break;
     751             :       case ExprType::B16x8:
     752           0 :         retObj = CreateSimd<Bool16x8>(cx, (int16_t*)retAddr);
     753           0 :         if (!retObj)
     754           0 :             return false;
     755           0 :         break;
     756             :       case ExprType::B32x4:
     757           0 :         retObj = CreateSimd<Bool32x4>(cx, (int32_t*)retAddr);
     758           0 :         if (!retObj)
     759           0 :             return false;
     760           0 :         break;
     761             :       case ExprType::Limit:
     762           0 :         MOZ_CRASH("Limit");
     763             :     }
     764             : 
     765           0 :     if (retObj)
     766           0 :         args.rval().set(ObjectValue(*retObj));
     767             : 
     768           0 :     return true;
     769             : }
     770             : 
     771             : bool
     772           0 : Instance::getFuncName(uint32_t funcIndex, UTF8Bytes* name) const
     773             : {
     774           0 :     return metadata().getFuncName(debug_->maybeBytecode(), funcIndex, name);
     775             : }
     776             : 
     777             : JSAtom*
     778           0 : Instance::getFuncAtom(JSContext* cx, uint32_t funcIndex) const
     779             : {
     780           0 :     UTF8Bytes name;
     781           0 :     if (!getFuncName(funcIndex, &name))
     782           0 :         return nullptr;
     783             : 
     784           0 :     return AtomizeUTF8Chars(cx, name.begin(), name.length());
     785             : }
     786             : 
     787             : void
     788           0 : Instance::ensureProfilingLabels(bool profilingEnabled) const
     789             : {
     790           0 :     return code_->ensureProfilingLabels(debug_->maybeBytecode(), profilingEnabled);
     791             : }
     792             : 
     793             : void
     794           0 : Instance::onMovingGrowMemory(uint8_t* prevMemoryBase)
     795             : {
     796           0 :     MOZ_ASSERT(!isAsmJS());
     797           0 :     ArrayBufferObject& buffer = memory_->buffer().as<ArrayBufferObject>();
     798           0 :     tlsData()->memoryBase = buffer.dataPointer();
     799             : #ifndef WASM_HUGE_MEMORY
     800             :     tlsData()->boundsCheckLimit = buffer.wasmBoundsCheckLimit();
     801             : #endif
     802           0 : }
     803             : 
     804             : void
     805           0 : Instance::onMovingGrowTable()
     806             : {
     807           0 :     MOZ_ASSERT(!isAsmJS());
     808           0 :     MOZ_ASSERT(tables_.length() == 1);
     809           0 :     TableTls& table = tableTls(metadata().tables[0]);
     810           0 :     table.length = tables_[0]->length();
     811           0 :     table.base = tables_[0]->base();
     812           0 : }
     813             : 
     814             : void
     815           0 : Instance::deoptimizeImportExit(uint32_t funcImportIndex)
     816             : {
     817           0 :     const FuncImport& fi = metadata(code().anyTier()).funcImports[funcImportIndex];
     818           0 :     FuncImportTls& import = funcImportTls(fi);
     819           0 :     import.code = codeBase(Tier::TBD) + fi.interpExitCodeOffset();
     820           0 :     import.baselineScript = nullptr;
     821           0 : }
     822             : 
     823             : void
     824           0 : Instance::ensureEnterFrameTrapsState(JSContext* cx, bool enabled)
     825             : {
     826           0 :     if (enterFrameTrapsEnabled_ == enabled)
     827           0 :         return;
     828             : 
     829           0 :     debug_->adjustEnterAndLeaveFrameTrapsState(cx, enabled);
     830           0 :     enterFrameTrapsEnabled_ = enabled;
     831             : }
     832             : 
     833             : void
     834           0 : Instance::addSizeOfMisc(MallocSizeOf mallocSizeOf,
     835             :                         Metadata::SeenSet* seenMetadata,
     836             :                         ShareableBytes::SeenSet* seenBytes,
     837             :                         Code::SeenSet* seenCode,
     838             :                         Table::SeenSet* seenTables,
     839             :                         size_t* code,
     840             :                         size_t* data) const
     841             : {
     842           0 :     *data += mallocSizeOf(this) + globals_->sizeOfMisc(mallocSizeOf);
     843             : 
     844           0 :     for (const SharedTable& table : tables_)
     845           0 :          *data += table->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenTables);
     846             : 
     847           0 :     debug_->addSizeOfMisc(mallocSizeOf, seenMetadata, seenBytes, seenCode, code, data);
     848           0 :     code_->addSizeOfMiscIfNotSeen(mallocSizeOf, seenMetadata, seenCode, code, data);
     849           0 : }
     850             : 
     851             : // We will emit SIMD memory accesses that require 16-byte alignment.
     852             : static const size_t TlsAlign = Simd128DataSize;
     853             : 
     854             : /* static */ UniqueGlobalSegment
     855           0 : GlobalSegment::create(uint32_t globalDataLength)
     856             : {
     857           0 :     MOZ_ASSERT(globalDataLength % gc::SystemPageSize() == 0);
     858             : 
     859           0 :     auto gs = MakeUnique<GlobalSegment>();
     860           0 :     if (!gs)
     861           0 :         return nullptr;
     862             : 
     863           0 :     void* allocatedBase = js_calloc(TlsAlign + offsetof(TlsData, globalArea) + globalDataLength);
     864           0 :     if (!allocatedBase)
     865           0 :         return nullptr;
     866             : 
     867           0 :     TlsData* tlsData = reinterpret_cast<TlsData*>(AlignBytes(size_t(allocatedBase), TlsAlign));
     868           0 :     tlsData->allocatedBase = allocatedBase;
     869             : 
     870           0 :     gs->tlsData_ = tlsData;
     871           0 :     gs->globalDataLength_ = globalDataLength;
     872             : 
     873           0 :     return gs;
     874             : }
     875             : 
     876           0 : GlobalSegment::~GlobalSegment()
     877             : {
     878           0 :     if (tlsData_)
     879           0 :         js_free(tlsData_->allocatedBase);
     880           0 : }
     881             : 
     882             : size_t
     883           0 : GlobalSegment::sizeOfMisc(MallocSizeOf mallocSizeOf) const
     884             : {
     885             :     // Note, once the GlobalSegment is shared among instances, we will have to
     886             :     // take that sharing into account.
     887           0 :     return mallocSizeOf(this) + mallocSizeOf(tlsData_);
     888             : }

Generated by: LCOV version 1.13